20200908のdockerに関する記事は11件です。

DjangoアプリケーションをDockerコンテナ上で動かす方法(開発および本番環境)

記事の概要

Djangoで作成したWEBアプリケーションを開発・本番環境で動作させる際はいくつかの方法があります。
最近では、Kubernetesが人気となりアプリケーションをコンテナ化する場面も多いです。

本記事では開発・本番環境でどのようにDjangoアプリケーションをのせたDockerコンテナを作るかについて記載します。

前提条件・環境

本記事で使用する環境はCentOS7DockerDjango2系です。

Dockerさえ動けばDockerコンテナは動くため、OSがWindowsでも問題ありません。

開発環境用Dockerコンテナ作成

使用するDockerファイル

開発環境用に使用するDockerファイルは以下になります。

このDockerファイルではdebian:10をベースにして、Pythonをソースコードからインストールしています。
公式PythonのDockerイメージもあるためそちらを使っても問題ないのですが、勉強のためにこのような構成になっています。

FROM debian:10

# Install Python3.7.7

WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
    gcc \
    libbz2-dev \
    libssl-dev \
    libffi-dev \
    libsqlite3-dev \
    make \
    tk-dev \
    zlib1g-dev \
    apache2-dev \
    python3-dev \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
    make && \
    make install && \
    make distclean && \
    ./configure && \
    make && \
    make altbininstall

# Install with pip

COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt

# Deploy App

WORKDIR /
ADD ./deployfiles.tar.xz .
WORKDIR /myapp

CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]

Dockerファイルの説明

FROM debian:10

まず、Dockerファイルを記載するときはベースとして何を使うか指定します。ここではdebian:10を指定しています。

FROM

# Install Python3.7.7

WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7

次にPythonのインストールです。

WORKDIRはOSのカレントディレクトリを移動させるような構文です。WORKDIR /workとすればルートディレクトリ(/)直下にworkというディレクトリが作られ(指定したディレクトリがなければ作られます)、そこがカレントディレクトリとなります。

ADDADD ホストOS上のパス Dockerコンテナ上のパスとすることで指定したホストOS上にあるファイルをDockerコンテナ上のパスへコピー・展開することができます。
ADDはCOPYと異なり、圧縮されたファイルを展開することができます。そのためtarxzなどのファイルはADDを使ってDockerコンテナ上へコピーすると良いと思います。

RUN apt-get update && apt-get install -y \
    gcc \
    libbz2-dev \
    libssl-dev \
    libffi-dev \
    libsqlite3-dev \
    make \
    tk-dev \
    zlib1g-dev \
    apache2-dev \
    python3-dev \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

RUNはDockerコンテナ上でコマンドを実行することが出来ます。apt-getを使用し、Pythonのインストールに必要な依存パッケージをインストールしています。

apt-get cleanrm -rf /var/lib/apt/lists/*は不必要なキャッシュやファイルを削除するために実行しています。これを削除することで、作成されるDockerイメージ容量を小さく保てます。

RUN ./configure --enable-shared && \
    make && \
    make install && \
    make distclean && \
    ./configure && \
    make && \
    make altbininstall

後は./configuremakemake installです。4行ほど余分なものがありますが、これはエラー対応のためにつけています。

何らかの組み合わせの問題だとは思うのですが、私が実行したときはこのようにしなければなりませんでした。もしかすると不要かもしれません。

# Install with pip

COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt

Pythonのインストールが終わったら、Pythonパッケージのインストールを行います。ここではpipコマンドを使用してrequirements.txtに記載されているパッケージをインストールします。

COPYはADDと似ていて、COPY ホストOS上のパス Dockerコンテナ上のパスとすることでホストOS上にあるファイルをDockerコンテナ上のパスへコピーできます。こちらは文字通りコピーしかしません。

後はRUNpipのアップグレードを行い、requirements.txtに基づいてPythonパッケージをインストールします。

# Deploy App

WORKDIR /
ADD ./deployfiles.tar.xz .
WORKDIR /myapp

CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]

最後に自分が作ったアプリケーションをDockerコンテナへ加えます。

deployfiles.tar.xzmyappというディレクトリを圧縮したもので、myapp直下にmanage.pyがあります。

CMDDockerコンテナが起動するときに実行するコマンドを設定する構文です。これはPythonのリスト形式のように記載でき、各要素は半角スペースで結合されます。つまり、以下のようなコマンドになります。

CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]
↓
python3 manage.py runserver 0.0.0.0:80

Dockerイメージのビルド

Dockerイメージをビルドするには以下のコマンドを実行します。

docker build -t test/myapp .

-tオプションはDockerイメージへタグを付けるために使用します。タグを付ければ管理がしやすくなります。

コマンドの最後にはDockerファイルのパスを入れます。ここではカレントディレクトリ(.)を指定しています。

デフォルトではDockerfileという名前のファイルを指定されたパスから探すため、上記で作成したファイル名はDockerfileとしておきます。

docker build

作成したイメージを確認するには以下のコマンドを実行します。

docker image ls

Dockerコンテナの起動

DockerイメージからDockerコンテナを起動するには以下のコマンドを実行します。

docker run --name myapp -d -p 80:80 -v /work/db.sqlite3:/myapp/db.sqlite3 test/myapp:latest

--nameオプションはDockerコンテナへ名前をつけます。これは後でこのDockerコンテナを停止、起動、削除したくなったりしたときに便利です。名前は一意なものになるため、名前をつけておけば名前を指定するだけで停止、起動、削除が出来ます。名前がない場合はコンテナIDを指定します。

-dオプションはバックグラウンドでコンテナを実行します。これをつけなかった場合は、Dockerコンテナの標準出力がコンソール上に表示されます。Ctrl + cで抜けられます。ほとんどの場合はバックグラウンドで動かすと思うのでつけておきます。

-pオプションはホストOSのポートDockerコンテナのポートを紐付けます。ホストOSのポート:Dockerコンテナのポートとします。今回はDjangoのプロセスをDockerコンテナの80番ポートを使用して公開しているため80を指定します。

-vオプションはホストOSのボリューム(DockerボリュームまたはホストOS上のファイルパス)Dockerコンテナのファイルパスを紐付けます。コンテナは終了したときにデータを保持しません。そのため、残しておきたいデータは外部に保管する必要があります。推奨はDockerボリュームですが開発環境のためホスト上OSのファイルパスへデータを保存させます。ここではdb.sqlite3ホストOSからDockerコンテナへ紐付けています。

test/myappは元になるDockerイメージの指定です。latestというのはバージョン名でDockerイメージをビルドしたときに何も指定しなければlatestになります。docker image lsで出力されるTAG列を参照することで確認できます。

docker run

正常に起動されているかどうかを確認するには以下のコマンドを実行します。

docker ps

STATUS列がUPになっていれば正常に起動しています。

何も出力されない場合は-aをつけて停止中のプロセスも確認します。もしDockerコンテナのログを確認したい場合は以下のコマンドを実行します。

docker logs [コンテナ名またはコンテナID]

エラーを確認して対応します。

Djangoアプリケーションへの接続

Dockerを起動しているホストOS上のIPアドレスの公開したポート番号へアクセスします。

本番環境用Dockerコンテナ作成

使用するDockerファイル

本番環境用に使用するDockerファイルは以下になります。

開発環境と違い、python3 manage.py runserverでプロセスを立ち上げるわけにはいきません。Apacheなどの上で動作させるほうが安定します。

ここではベースとしてhttpd:2.4を使用しています。Apache Web サーバ公式Dockerイメージです。

ApacheDjangoを実行するためにはmod_wsgiというモジュールをApacheへ組み込む必要があります。そのためPythonmod_wsgiをインストールしています。

FROM httpd:2.4

# Install Python3.7.7

WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
    gcc \
    libbz2-dev \
    libssl-dev \
    libffi-dev \
    libsqlite3-dev \
    make \
    tk-dev \
    zlib1g-dev \
    apache2-dev \
    python3-dev \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
    make && \
    make install && \
    make distclean && \
    ./configure && \
    make && \
    make altbininstall

# Install with pip

COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt

# install ModWsgi

WORKDIR /work
ADD ./mod_wsgi-4.7.1.tar.gz .
WORKDIR mod_wsgi-4.7.1
RUN ./configure \
    --with-apxs=/usr/local/apache2/bin/apxs \
    --with-python=/usr/local/bin/python3.7 && \
    make && \
    make install 

# Set Apache

WORKDIR /usr/local/apache2/conf
COPY ./httpd.conf .
COPY ./server.crt .
COPY ./server.key .
COPY ./wsgi.conf ./extra
COPY ./httpd-ssl.conf ./extra

Dockerファイルの説明

FROM httpd:2.4

ベースとしてhttpd:2.4を指定しています。

# Install Python3.7.7

WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
    gcc \
    libbz2-dev \
    libssl-dev \
    libffi-dev \
    libsqlite3-dev \
    make \
    tk-dev \
    zlib1g-dev \
    apache2-dev \
    python3-dev \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
    make && \
    make install && \
    make distclean && \
    ./configure && \
    make && \
    make altbininstall

開発環境と同様にPythonをインストールします。

# Install with pip

COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt

開発環境と同様にpiprequirements.txtに基づいたPythonパッケージをインストールします。

# install ModWsgi

WORKDIR /work
ADD ./mod_wsgi-4.7.1.tar.gz .
WORKDIR mod_wsgi-4.7.1
RUN ./configure \
    --with-apxs=/usr/local/apache2/bin/apxs \
    --with-python=/usr/local/bin/python3.7 && \
    make && \
    make install 

ApacheDjangoを動作させるためにmod_wsgiをインストールします。

# Set Apache

WORKDIR /usr/local/apache2/conf
COPY ./httpd.conf .
COPY ./server.crt .
COPY ./server.key .
COPY ./wsgi.conf ./extra
COPY ./httpd-ssl.conf ./extra

最後にApacheの各種configファイル、証明書関連ファイルをコピーします。

Dockerイメージのビルド

開発環境と同様です。

Dockerボリュームの作成

Dockerボリュームを作成するには以下のコマンドを実行します。

docker volume create --name volume-name

--nameで指定した名前でDockerボリュームが作成されます。このボリュームはDockerコンテナと紐付けます。

Dockerボリュームの寿命はDockerコンテナと異なります。DockerコンテナがなくなってもDockerボリュームは存在し続けるため、データを永続化できます。

Dockerコンテナの起動

DockerイメージからDockerコンテナを起動するには以下のコマンドを実行します。

docker run --name myapp -d -p 443:443 -v vlume-name:/myapp test/myapp

-vオプションだけ開発環境とは異なります。ここではホストOS上のファイルパスではなく、Dockerボリュームを指定しています。volume-nameという名前のDockerボリュームDockerコンテナ上の/myappと紐付きます。これで/myapp上にあるデータがDockerボリュームへ保存されます。

Djangoアプリケーションへの接続

開発環境と同様です。

使用したソースファイル

Python

mod wsgi

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

udemyの講座でCentOS7を使ってyum -y install dockerした際にCannot find a valid baseurl for repoとエラーが出た場合の対処法

状況

udemy
Linuxコマンドから始めるDocker ~ BE A FIRST PENGUIN AND GROW AS WHALE
https://www.udemy.com/course/linuxdocker-be-a-first-penguin-and-grow-as-whale/learn/lecture/16684274#questions/12224904
セクション3−15

にて、CentOSをインストール後

# yum -y install docker

した際に

Cannot find a valid baseurl for repo

とエラーが出ました。
CentOSは、そのままインストールしただけではyumコマンドが使えないことがあります。
少なくとも、私が使用したCentOS7.8.2003ではそうでした。

環境

macでVirtualBox上にLinux(CentOS7.8.2003)をインストール
rootユーザーで全操作を行った

CentOSをインストール後、dockerをインストールしようとしたらエラーになった

# yum -y install docker

スクリーンショット 2020-09-05 23.55.35.png

1.ONBOOTの記述の変更とDNSの設定をする

以下を開きます。

# vi /etc/sysconfig/network-scripts/ifcfg-???

???は

# cd /etc/sysconfig/network-scripts
# ls

でご自身のディレクトリを確認して入力してください。
私の場合はifcfg-enp0s3とifcfg-enp0s8の二つが存在しましたが、ifcfg-enp0s3のみで行っています。

開いた先でONBOOTの記述を"no"から"yes"に変更し、DNSの設定を記述します。

ONBOOT=yes

DNS1=8.8.8.8
DNS2=8.8.4.4

2.再起動

設定が終わったら再起動をします。

# systemctl restart network

以上でうまくいかなかった場合はLinuxを再起動してみてください。

3.確認

念の為動作確認をします。
試しにupdateしてみました。

# yum update

ちゃんと動きました。
スクリーンショット 2020-09-08 12.47.56.png

4.Dockerのインストール

# yum -y install docker

無事ダウンロードできました。
スクリーンショット 2020-09-08 13.16.13.png

もしうまく動かなかったらbaseurlを書き換える

それでも動作が思う通りにならなければbaseurlに問題があるかもしれません。

# vi /etc/yum.repos.d/CentOS-Base.repo

初期状態
スクリーンショット 2020-09-05 23.57.15.png

全てのbaseurlを以下の記述に変更します。

#baseurl=http://ftp-srv2.kddilabs.jp/Linux/packages/CentOS/7.8.2003/os/x86_64/

編集後
スクリーンショット 2020-09-05 23.59.45.png

お使いのバージョンのURLで設定してください。
私は以下のサイトから
https://blog.77jp.net/linux-iso%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8-%E3%81%AE%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%82%B5%E3%82%A4%E3%83%88%E5%9B%BD%E5%86%85%E3%83%9F%E3%83%A9%E3%83%BC

http://ftp-srv2.kddilabs.jp/Linux/packages/CentOS/
を開き
自分のバージョン ➡︎ os/ ➡︎ x86_64/
と開いたURLをbaseurlに設定しています。

参考

https://mebee.info/2020/03/21/post-7689/
https://qiita.com/ntkgcj/items/fd8588dcd65a42c34875

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでApicurio Studioをホスティングした

Apicurio Studio使ってますか。
私は先日使い始めました。
まだ良くわかっていません。

Dockerでホスティングしたのですが、
その道が想像以上に険しかったので、あとに続く人のために遺しておきます。

Apicurio Studioとは?

Apicurio Studio(アピクリオ・スタジオ)はApicurioプロジェクトのひとつで、
OSSのOpenAPI設計ツールです。
OpenAPIのツールといえばSwaggerが有名ですが、
複数人で作業するとなると有料プランを利用しないといけません。
Swagger以外にもツールはあるそうですが、結構有料のものばかり(くわしくはこちら)。
業務ならまだしも、趣味開発では支出を避けたいところです。

そこで、OSSのApicurio Studioを知りました。
無料というだけでなく、WebのGUIベースの操作で設計できるのも魅力じゃないでしょうか。
モックやテストといった機能はまだなくて後日追加予定らしいですが、タダなら試してみる価値はあると思います。
活発さはぼちぼちです。

運用方法

Apicurio Studioを使うには次の3つの方法があります。

  1. 公式がお試し用として配信しているLiveバージョンを使う
  2. ローカルマシンでホスティングする
  3. Dockerでホスティングする

2はダウンロードしてすぐ使えるスクリプト込の「クイックスタート」が楽だと思います。
3もdocker-composeを簡単に実行できるスクリプトがGitHubにあります。

本格運用するなら2か3でしょうが、私はサーバー群をdocker-composeで運用しているので、Apicurio StudioもDockerで立てようと思います。
さらに、上記で述べたGitHubで公開されているスクリプトではDBやらURLの融通が聞かないので、自前でやろうと思います。

ちなみに、公式ドキュメントはあまり親切ではありません。
Dockerイメージのページにある説明も簡素なもので、結構試行錯誤しました。
現状動いているので大丈夫だとは思いますが、なにか間違っていればコメントでご指摘いただけると幸いです。

アーキテクチャ

Apicurio StudioをDockerで運用するには、アーキテクチャの理解が不可欠です。
1サービスとは思えない構造で、4つのイメージから成っています。

図はOpenShiftと書いてありますが、Dockerでも同じです。

図内の表記 イメージ名 役割
Angular based UI application, Apicurio Studio UI Component apicurio-studio-ui フロントエンド
Apicurio Studio API Component apicurio-studio-api バックエンド
Apicurio Studio WebSocket Component apicurio-studio-ws 編集画面の同期用WebSocket
KEYCLOAK apicurio-studio-auth ユーザー認証

この構成にならってもいいんですが、
この中のapicurio-studio-authはDBがH2限定なんで、KEYCLOAKは別途イメージから作ろうと思います。
よって、今回作るのは以下のような構成になります。

イメージ コンテナ名
postgres pg
nginx deploy
jboss/keycloak keycloak
apicurio/apicurio-studio-ui apicurio-ui
apicurio/apicurio-studio-api apicurio-api
apicurio/apicurio-studio-ws apicurio-ws

ドメインはこの記事ではexample.comとします。

docker-composeの設定

以下のdocker-compose.ymlファイルでコンテナを起動します。
起動時にDBの初期化があるので、pgを先に起動し、設定したあとで他のコンテナを起動します。

docker-compose.yml
version: '3'                                              

services:
    pg:
        image: postgres
        restart: always
        environment:
            POSTGRES_USER: xxxx
            POSTGRES_PASSWORD: xxxxxx
        volumes:
            

    deploy:                                               
        image: nginx                                      
        restart: always                                   
        ports:
            - 80:80
            - 443:443
        volumes:
            

    keycloak:
        image: jboss/keycloak
        restart: always
        environment:
            DB_VENDOR: postgres
            DB_ADDR: pg
            DB_PORT: 5432
            DB_DATABASE: keycloak
            DB_USER: xxxx
            DB_PASSWORD: xxxxxx
            KEYCLOAK_USER: admin
            KEYCLOAK_PASSWORD: XXXXXX
        volumes:
            

    apicurio-api:
        image: apicurio/apicurio-studio-api
        restart: always
        environment:
            APICURIO_KC_AUTH_URL: https://keycloak.example.com/auth/
            APICURIO_HUB_STORAGE_JDBC_TYPE: postgresql9
            APICURIO_DB_DRIVER_NAME: postgresql
            APICURIO_DB_CONNECTION_URL: jdbc:postgresql://pg:5432/apicurio
            APICURIO_DB_USER_NAME: xxxx
            APICURIO_DB_PASSWORD: xxxxxx
            APICURIO_DB_INITIALIZE: "true"
            APICURIO_HUB_STORAGE_JDBC_INIT: "true"
        depends_on:
            - pg
            - apicurio-ws

    apicurio-ws:
        image: apicurio/apicurio-studio-ws
        restart: always
        environment:
            APICURIO_KC_AUTH_URL: https://keycloak.example.com/auth/
            APICURIO_HUB_STORAGE_JDBC_TYPE: postgresql9
            APICURIO_DB_DRIVER_NAME: postgresql
            APICURIO_DB_CONNECTION_URL: jdbc:postgresql://pg:5432/apicurio
            APICURIO_DB_USER_NAME: xxxx
            APICURIO_DB_PASSWORD: xxxxxx
            APICURIO_DB_INITIALIZE: "true"
            APICURIO_HUB_STORAGE_JDBC_INIT: "true"
        depends_on:
            - pg

    apicurio-ui:
        image: apicurio/apicurio-studio-ui
        restart: always
        environment:
            APICURIO_KC_AUTH_URL: https://keycloak.example.com/auth/
            APICURIO_UI_HUB_API_URL: https://apicurio-api.example.com
            APICURIO_UI_EDITING_URL: wss://apicurio-ws.example.com
        depends_on:
            - pg
            - apicurio-api
            - apicurio-ws

postgreSQLの設定

keycloakとApicurio Studioで使うデータベースを作成しておきます。

データベースの作成
create database keycloak;
create database apicurio;

nginxの設定

Apicurio StudioはJavaScriptでAPIやWebSocketにアクセスするので、
複数のコンテナすべてのポートをホストのポートとバインドする必要があります。
でもそんなにいくつもポートを使っていると、何番が何だったとか、ポートフォワーディングの設定が大変なので、
リバースプロキシを挟んで起きます。
nginxコンテナの80と443だけをホストとバインドし、すべてのWeb通信はnginxを通します。

リバースプロキシを設定して、docker-compose.yml内に記述したURLでそれぞれアクセスできるようにします。
※常時SSL設定などは省略しています。

nginx_apicurio.conf
# keycloak
server {
    listen       443 ssl;
    listen [::]:443 ssl;
    server_name  keycloak.example.com;

    location / {
        include /etc/nginx/params/proxy_params;
        proxy_pass https://keycloak:8443;
    }
}

# ui
server {
    listen       443 ssl;
    listen [::]:443 ssl;
    server_name  apicurio.example.com;

    location / {
        include /etc/nginx/params/proxy_params;
        proxy_pass http://apicurio-ui:8080;
    }

    location /studio {
        return 301 https://$host;
    }
}

# api
server {
    listen       443 ssl;
    listen [::]:443 ssl;
    server_name  apicurio-api.example.com;

    location / {
        include /etc/nginx/params/proxy_params;
        proxy_pass http://apicurio-api:8080;
    }
}

# ws
server {
    listen       443 ssl;
    listen [::]:443 ssl;
    server_name  apicurio-ws.example.com;

    location / {
        include /etc/nginx/params/proxy_params;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://apicurio-ws:8080;
    }
}

Keycloakの設定

Keycloakはシングルサインオンを提供するOSSです。
予めアプリケーションを登録しておき、
アプリケーションからKeycloakにリダイレクト、認証したらKeycloakからアプリケーションにリダイレクトすることで、ログイン情報を認証します。

Keycloakにアプリケーションを登録するには、realmと呼ばれるプロジェクトのようなもの、clientと呼ばれるアプリケーションを作成する必要があります。
設定項目が多くて大変なので、設定済みのものを拝借しましょう。

apicurio-studio-authからの設定エクスポート

上記apicurio-studio-authイメージには諸々設定済みのKeycloakが用意されています。
なので、apicurio-studio-authイメージでコンテナを起動し、Apicurioのrealm情報をエクスポートし、今回用意したKeycloakにインポートすればいいです。

まずはコンテナを起動します。
8080ポートに接続できるようにし、管理画面へのログイン情報を環境変数で渡しておきます。

コンテナの起動
docker run -it -p 8080:8080 \
-e "APICURIO_KEYCLOAK_USER=admin" \
-e "APICURIO_KEYCLOAK_PASSWORD=admin" \
-e "APICURIO_UI_URL=https://apicurio.example.com/" \
apicurio/apicurio-studio-auth

起動したら、ブラウザでhttp://localhost:8080/auth/にアクセスしてログインします。
上記コマンドで起動した場合、ID:admin、password:adminでログインします。
左上でApicurioが選択されていることを確認し、最下部のExportをクリックします。
image.png

(一応)2つの項目をONにし、Exportを押します。
しばらくするとjsonファイルがダウンロードできます。
image.png

realmのインポート

先程ダウンロードしたjsonを今回用意するKeycloakにインポートします。
コンテナが起動したら、ブラウザでhttps://keycloak.example.com/auth/にアクセスし、ログインします。

「Master」というデフォルトのrealmが選択されているはずなので、「Add realm」から先程のjsonをインポートします。

ログインできるよう設定

ログインページの形式を決めます。

image.png

設定完了(のはず)

https://apicurio.example.comにアクセスすると、ログイン画面が表示されます。
image.png

ユーザー登録をするとログインできます。
APIの追加、編集をしてみて、動けば成功です。
失敗しててもめげずに、あれこれいじってみてください。
ブラウザのコンソール、各コンテナのログを見れば解決できると思います。

間違えても簡単にやり直せます。Dockerならね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails + mysql5.7で"Mysql2::Error: Expression #1 of ORDER BY clause is not in SELECT list, references column 'テーブル名.カラム名' which is not in SELECT list "

環境

ruby 2.5.1
rails 5.2.4
mysql 5.7

背景

railsのDBをmysqlに変えて、rspecを実行したら、見慣れぬエラーが発生

ActionView::Template::Error:
   Mysql2::Error: Expression #1 of ORDER BY clause is not in SELECT list, references column
   'portfolio1_test.users.name' which is not in SELECT list; this is incompatible with DISTINCT:
    SELECT  DISTINCT `communities`.* FROM `communities` LEFT OUTER JOIN `community_users` ON
   `community_users`.`community_id` = `communities`.`id` LEFT OUTER JOIN `users` ON `users`.`id` = 
   `community_users`.`user_id` ORDER BY `users`.`name` DESC, created_at DESC LIMIT 15 OFFSET 0

原因

Mysqlから以下の設定が追加されたために問題が発生していたらしい
sql_mode,'ONLY_FULL_GROUP_BY

解決策1

上記の設定が影響するSQL文を変える
MySQL5.7にアップデートしたらonly_full_group_byでエラーになった

解決策2

Mysqlの設定を変える
Ransack の sort_link が MySQL で動作しない( incompatible with DISTINCT)

今回はMysqlの設定を変えることにした

変更する箇所が多すぎるので、Mysql の設定を変えることにした。
ローカルでは設定を変えることで、問題が解決するが、Docker 環境でもこの設定変更を実行させたい。

docker-compose.yml にて command を使って、設定を変更できるはず。

コンテナを構築する際に、Mysqlの設定を反映させたい

MySQL 5.7 のONLY_FULL_GROUP_BY が出た時にDockerでやった対処

docker-compose.yml
version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    tty: true
    stdin_open: true
    depends_on:
      - db
    ports:
      - "3000:3000"
    volumes:
      - .:/myapp:delegated
  db:
    image: mysql:5.7
    command:
      - --sql-mode=NO_ENGINE_SUBSTITUTION   #追加!!
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3316:3306'
    volumes:
      - ./db/mysql/volumes:/var/lib/mysql
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerを使ったデータ解析環境の構築(個人的備忘録)

Dockerfileの作成

Dockerfile
FROM ubuntu:latest
# -yはインストールの際全てyesで答え、インストールする
RUN apt-get update && apt-get install -y \
# ubuntu上でroot以外のユーザーがroot権限でコマンドを打ちたい時に使用
    sudo \
# httpを使ってデータをダウンロードする
    wget \
# エディター
    vim
# anacondaのインストローラの保存場所
WORKDIR /opt
# anacondaのインストローラをダウンロードする。
RUN wget https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh

apt-getはubuntuのパッケージ管理ツールで、「\」区切りでパッケージを分けて記述すると、何がインストールされているのかが分かり易い

Dockerfileでコンテナのビルド

-#これでubuntuのパッケージと、optディレクトリの中にanacondaのインストローラがダウンロードされる。
% docker build .
-# 作成したコンテナの起動
% docker run -it コンテナID bash
-# optになっているのは「WORKDIR /opt」の指定があるため
-# インストローラがあることを確認する。
root@85a5e79aa6c2:/opt# ls
Anaconda3-2019.10-Linux-x86_64.sh
-# インストローラの実行
# sh Anaconda3-2019.10-Linux-x86_64.sh

1.エンターを押し続ける
2.yesと答える
3.どこにインストールするか聞かれるので/opt/anaconda3とする
4.init(初期化)するか聞かれるので、yesと答える
5.「Thank you for installing Anaconda3!」と表示されたらダウンロードされている。
しかしながらパスを通していないため、「python」は使えない。

パスを通すとは

環境変数$PATHに、パスを追加することでコンピュータがプログラムをそのパスから探してきてくれる。

環境変数の確認

# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

pythonを探す

-# 「anaconda3」ディレクトリに移動
# cd anaconda3
-# 「bin」ディレクトリに移動
# cd bin
-# 「python」の起動
# ./python
-# パスの確認
# pwd

Pythonが起動したのが確認できる。つまりパスを通すとは「/opt/anaconda3/bin」を通す。

パスを通す

-# pythonから出る。
>>> exit()
-# パスの追加(=の両隣に半角スペースは無し)
# Export PATH=/opt/anaconda3/bin:$PATH
-# パスの確認
# echo $PATH
-#/opt/anaconda3/binが追加されていることがわかる。
/opt/anaconda3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-# 「opt」に移動
# cd /opt
-# pythonの起動確認
# python

パスを通したことにより、Pythonが「opt」ディレクトリでも起動したことがわかる。

インストローラのオプションの確認

-# sh -x インストローラのファイル
# sh -x Anaconda3-2019.10-Linux-x86_64.sh

Anaconda2-2019.10-Linux-x86_64.shに使えるオプションが表示され今回は-b-pを使う。
-bはバッチモードで起動。Dockerfileで使う場合に使用。インタラクティブな操作を回避する。
-pはデフォルトは「/root/anaconda3」で、指定することで任意の場所にインストールできる。
再度「anaconda3」を消してインストールできるか確認する。

-# anaconda3の削除
# rm -r anaconda3/
-# インストローラからダウンロード及びoptディレクトリ内にanaconda3の作成
# sh Anaconda3-2019.10-Linux-x86_64.sh -d -p /opt/anaconda3

異常なくダウンロードされたことが確認できる。

Dockerfileの更新

Dockerfile
FROM ubuntu:latest
RUN apt-get update && apt-get install -y \
    sudo \
    wget \
    vim
WORKDIR /opt
#------------ここから変更------------#
RUN wget https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh && \
# インストローラからダウンロード及びoptディレクトリ内にanaconda3の作成
    sh https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh -b -p /opt/anaconda3 && \
# インストローラーの削除
    rm -f Anaconda3-2019.10-Linux-x86_64.sh
# パスを通す$PATHは自己参照
ENV PATH /opt/anaconda3/bin:$PATH
# 「pip」はpythonのパッケージを管理するツール
RUN pip install --upgrade pip
CMD [ "jupyter","lab","--ip=0.0.0.0","--allow-root","--LabApp.token=''" ]

Dockerfileでコンテナのビルド

% docker build .
% docker run -p 8888:8888 作成したコンテナID

これでコンテナにjupyterlabが立ち上がり、localhost:8888で接続できることが確認できる。

ファイルシステムの共有

-# どこでもいいので共有するファイルを作成する
% mkdir ds_python
-# 共有するファイルのパスの確認
% pwd
-# コンテナの共有ファイルは今回は「work」ディレクトリとする。コンテナ名は「my-lab」
% docker run -p 8888:8888 -v 共有するファイルのパス:/work --name my-lab 作成したimage名

localhost:8888で確認し、「work」ディレクトリが作成されていることを確認する。
jupyterlabでworkディレクトリで何かしらファイルを作成し、ホスト側の「ds_python」ファイルの中身を確認し、jupyterlabで作成したファイルが存在していることを確認する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace. への対処法

タイトルの通りですが、今回は

.env
ERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace.

というエラーが出た際の対処法について、私の環境下でのソリューションを共有したいと思います。

私はRuby on Railsでプログラミング学習を開始して1ヶ月ほどの初学者ですので、至らない点や説明不足の点等もあるかと思います。
お気づきの点等ございましたらご指摘いただけると幸いです。

※できるだけ初学者の方にも分かりやすく説明する事を心がけているため、やや冗長に感じる部分もあるかもしれませんがご了承くださいませ。

環境

・Ruby 2.6.5
・Rails 5.2.3
・MySQL 5.7
・Docker
・Dokcer-compose version: '3'

まずは解決した方法から

早速ですが解決方法から述べたいと思います。

私の環境下では、ルートディレクトリ
(DockerfileやGemfile等のファイルと同じ階層)
に存在する.envファイルの記述が間違っていた事が原因でした。

.env
#こちらがエラーが出てしまう記述
THOR_SILENCE_DEPRECATION = true


#以下の記述に修正すればエラーは解消される
THOR_SILENCE_DEPRECATION=true

エラーが出てしまう記述では、余計な空白が入ってしまっていますね。
空白を除去する事で、上記エラーは解消されます。

エラーの深掘り

エラーの内容を再度見てみましょう。

.env
ERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace.

こちらの文章をGoogle翻訳で日本語に修正してみると、

エラー:ファイル./.env:環境変数名 'THOR_SILENCE_DEPRECATION'に空白が含まれていない可能性があります。

と変換されます。

日本語としては若干分かりづらいのですが、なんとなく

「空白の関係でエラーが出ているのだな」

とアタリをつける事ができます。

エラー文本文でググってみると、完全に同じエラー文が出てきた方はいらっしゃいませんでしたが、解決にあたっては以下のブログを参考にさせていただきました。

Composerで.env内のスペースはクォートで囲む必要があるエラーが発生
https://awesome-linus.com/2019/04/07/composer-install-error-need-quotes/

エラー文でググったところ情報が少なかったため、おそらくそう頻繁に出るエラーではないのだと予測できますが、初学者の方がエラーに遭遇した際の一つのソリューションとして参考になれば幸いです。

エラーが起きた背景を詳しく

エラーが起きた背景について、もう少し詳しく記述していきます。

このエラーは「.envファイル」の記述が間違えているのが原因なのですが、そもそも.envファイルを触った事がないという方もいらっしゃるかも知れません。

私も約1ヶ月ほどRailsを勉強してきた中で、.envファイルを触る機会というのは一度もなかったのですが、ログイン機能を実装するGem「sorcery」を導入する過程で、以下のエラーを解決するために.envファイルを触る必要が出てきました。

Deprecation warning: Expected string default value for '--test-framework'; got false (boolean).
This will be rejected in the future unless you explicitly pass the options `check_default_type: false` or call `allow_incompatible_default_type!` in your code
You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.

こちらのエラーは、

・Gemfileにsorceryを追加
・bundle install
・sorceryを使用するためのコマンド「rails g sorcery:install」を実行

という過程の中で発生したものです。

エラーの詳細については私もよく分かってはいないのですが、どうやらシェルスクリプトを生成するためのGemからエラーが出ているらしいとのこと。

このエラーを解決するための方法として、.envファイルに

.env
#正しい記述
THOR_SILENCE_DEPRECATION=true

の記述を追加する必要があり、
誤って以下のコードを記述。

.env
#不要な空白があるためエラーが出る記述
THOR_SILENCE_DEPRECATION = true

そして、rails g controller ~~
を実行しようとしたところ、タイトルのエラーが発生したという経緯です。

ちなみに、「Deprecation warning〜〜〜」のエラーに関しては、以下の記事

[Ruby on Rails]環境変数の設定方法(.bash_profile、Dotenv-rails)
https://qiita.com/yuichir43705457/items/7cfcae6546876086b849

RSpecを導入する
https://qiita.com/d0ne1s/items/1ecd114b33e80058215f

を参考に解決する事ができました。
ありがとうございました。

おしまい

以上が、今回のエラーの解決方法と周辺情報です。
あまり情報が多くないエラーでしたので、もし遭遇して困っている方は参考にしていただけると幸いです。
また、説明が分かりづらい点等があれば、ご指摘いただければと思います。

それでは、最後までお付き合いいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FluxでGitOpsフローを構築してリリースした話

どういう話

先日リリースされたサービスで、自分がインフラとそれに付随するデプロイフローを構築したので、その備忘録。

あと、k8s周りを調べるとハンズオンが結構多かった印象だったので、実際にリリースまでしたものをアウトプットしたかった。

前提

Fargateを利用していますが、Fargate特有の話はあまりないです。
アプリケーションコードはGitHub, インフラコードはCodeCommitで管理しています。

※インフラコードをCodeCommitで管理している理由は、コード上に時々必要になる12桁のAWSIDは秘匿情報と考えており、
これを(privateとはいえ)GitHub上のリポジトリで管理するのは得策ではないと考えたためです。
CodeCommit上であれば、そもそもCodeCommitにアクセスするのにAWSの認証が必要なので安全であると考えています。
Fargateでは当時kubernetes-external-secretsなどを使うことができなかったための苦肉の策です。

出てくるもの

Flux GitOpsフローを構築するのに使っています(メインの話)
FluxCloud FluxからのイベントをキャッチしSlackに通知するためにつかってます

GitOpsって何?

WeaveWorksが提唱するデプロイフローです。

Guide To GitOps
コマンドラインツールを用いずにCI/CDを行うGitOpsとは?

超絶簡単に言うと、"全ての変更はGit上のコードとして履歴が管理される"フローです。

デプロイフロー

メインの話です。
GitOpsを提唱しているWeaveWorksが開発しているFluxを用いたフローを構築しました。

アプリケーションコードの場合

85833815-4a3e5880-b7cd-11ea-9e42-056fea792991.png

  1. githubにアプリケーションコードをcommitする
  2. CicleCIがECRにイメージをpush
  3. イメージのpushを検知したfluxがCodeCommit上のmanifestファイルを更新してcommit
  4. 更新されたmanifestファイルを元にfluxがk8sクラスターを更新する

インフラ(k8s)コードの場合

85834239-fed87a00-b7cd-11ea-8444-b523fd8dc758.png

  1. CodeCommitにcommitする
  2. commitをfluxが検知し、manifestファイルを元にk8sクラスターを更新する

Flux設定

Fluxのdeployment.ymlは最初から色々なものが書かれていますが、触ったところは大きく2つです。

  1. gitリポジトリとECR設定
deployment.yml
args:
- --git-url=ssh://********************@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/*********
- --git-branch=master
- --git-path=k8s/production
- --git-label=flux
- --git-user=flux
- --git-email=flux@example.com
- --registry-ecr-region=ap-northeast-1
- --registry-ecr-exclude-id=[]
  1. fluxcloud設定
deployment.yml
args:
- --connect=ws://fluxcloud

デプロイ方法

staging

developブランチにpushされると自動でstaging環境にデプロイされます。

config.yml
register_staging_image:
  jobs:
    - aws-ecr/build-and-push-image:
        executor:
          name: aws-ecr/default
          use-docker-layer-caching: true
        account-url: ECR_URL
        create-repo: false
        dockerfile: .dockerenv/Dockerfile.production
        path: .
        region: AWS_DEFAULT_REGION
        repo: STG_REPO_NAME
        tag: "${CIRCLE_SHA1}"
        filters:
          branches:
            only: develop

production

github上でmasterブランチに対してリリースタグを打つとproduction環境にデプロイされます。

リリースバージョンは1.0.0や1.0.0.0.1など、数字とピリオドの組み合わせのみにしてあります。

config.yml
register_production_image:
  jobs:
    - aws-ecr/build-and-push-image:
        executor:
          name: aws-ecr/default
          use-docker-layer-caching: true
        account-url: ECR_URL
        create-repo: false
        dockerfile: .dockerenv/Dockerfile.production
        path: .
        region: AWS_DEFAULT_REGION
        repo: PRD_REPO_NAME
        tag: "${CIRCLE_TAG}"
        filters:
          branches:
            ignore: /.*/
          tags:
            only: /[0-9]+(\.[0-9]+)+/

ロールバック

FluxがcodeCommit上の変更を検知してk8sクラスターを更新してくれるので、
codeCommit上で目当てのバージョンまでrevertするか、イメージタグを変更してcommitすると変更できます。

デプロイ通知

FluxCloudを用いてwebhookを通じてSlackにデプロイ通知を送信しています。

deployment.yml
        - name: SLACK_URL
          value: "https://hooks.slack.com/services/******/**********/**************"
        - name: SLACK_CHANNEL
          value: "channel"
        - name: SLACK_USERNAME
          value: "Production Deployment"
        - name: SLACK_ICON_EMOJI
          value: ":kyaru-chan:"
        - name: GITHUB_URL
          value: "https://ap-northeast-1.console.aws.amazon.com/codesuite/codecommit/repositories/**********"

総括

少し前まではcapistranoなどを使って手作業でデプロイしていたので、相当楽で便利になりました。
このフローを最初に作ってしまえばエンジニアは開発に集中できるし、デザイナーやコーダーといった方のコミットでも自動でstagingにデプロイされるので、ある意味エンジニアを開放しているのかもしれないです。

アプリケーション周りも頑張ったのでそっちも書くかもしれません

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub ActionsでDockerコンテナをGitHub Package RegistryやDocker Hubにpushした話

この記事はお試しで 自分のブログ と同じ内容を投稿しています。

GitHub ActionsでDockerコンテナをGitHub Package Registryにpushした話をしようと思います。

想定読者

  • dockerのビルドがなんとなくわかる

背景

現在私は会社のベースイメージとして使えるように

https://github.com/fagai/docker-php

というgithubリポジトリでDocker Hubにautomated buildを設定してDocker Hubからビルドを行っていました。
Docker Hubのビルドタイムラインは非常に遅くて、ちょいちょいストレスになりつつもなんとか続けていました。

ただ、最近になってDocker Hubのpull制限だったりとか、GitHubがContainer Registryがパブリックベータになったりしてどうにかしたいなぁと思いまして、GitHub ActionsでBuild+Pushすることにしました。

GitHub Container Registry(GCR)とGitHub Package Registry(GPR)は違う

ここから、GitHub Container RegistryをGCRと省略します、決してGoogle Container Registryではないですので注意してください。(略が被るの困るね)

前者は先日パブリックベータとして出たほうで、後者は少し前からあったものです。
2つの違いは

  • URLが異なる(ghcr.ioとdocker.pkg.github.com)
  • ユーザ(or Organization)に紐づくか、Repositoryに紐づくかが違う

といったところです。

紐づく部分に関してはURLのパスも以下のように違います。

  • ghcr.io/OWNER/IMAGE_NAME
  • docker.pkg.github.com/OWNER/REPOSITORY/IMAGE_NAME

こんな感じでユーザに紐づくかリポジトリに紐づくか違います。
まあ、以下に書いていく内容はどちらでも同じように書くことが可能なので、Package Registryなんだ・・・ってなっても見ると良いと思います。

もともと私はGitHub Container Registryを使おうとしてましたが、ドメインがghcr.ioとなっておりなんだろうこれ・・・GitHubじゃないんじゃね・・・?とか思っちゃってGitHub Package Registryを使いだした次第です。
現状で言えばGCRのほうがmanifestのバージョンが新しかったりして使う分にはGCRのほうがいいと思います。パッケージに紐付けたいときはGPRを利用しましょう。

最初やったとき

最初はstarter-workflowのdocker publishを使ってました。

https://github.com/actions/starter-workflows/blob/master/ci/docker-publish.yml

当時のやつ
https://github.com/fagai/docker-php/blob/32988eacf16e697e5376ee0af778079fa1e0fb62/.github/workflows/docker-publish.yml

DockerHubと比べてQueueに積まれる時間もないのでめちゃくちゃ良かったです。

次第に

次第にDockerHubにもpushできないかと思って、探した結果 https://github.com/docker/build-push-action を見つけてこちらに書き換えることに。

https://github.com/docker/build-push-action

当時の:https://github.com/fagai/docker-php/blob/12d060efd0b91924f0edf85f3b127e19d47cd18a/.github/workflows/docker-publish.yml

- name: Push to GitHub Packages
  uses: docker/build-push-action@v1
  with:
    dockerfile: ${{ matrix.images }}/Dockerfile
    username: ${{ github.actor }}
    password: ${{ secrets.CR_PAT }}
    registry: docker.pkg.github.com
    repository: fagai/docker-php/${{ env.IMAGE_NAME }}
    tags: ${{ env.IMAGE_VERSION }}

スリム~~。
CR_PATの箇所ですが、Container Registry Personal Access Tokenとかの略なんでしょうか、実はstarter-workflowのときにそう書いてあったのでその名前でgithubのtokenをセットしました。(github.tokenでも良いのですが、access tokenをできる限り絞ったほうが良いらしくaccess repositoryとwrite repositoryだけの権限をつけました)

後にDocker Hubのpushの設定もつけました。

- name: Push to Docker Hub
  uses: docker/build-push-action@v1
  with:
    dockerfile: ${{ matrix.images }}/Dockerfile
    username: ${{ github.actor }}
    password: ${{ secrets.DOCKER_HUB_TOKEN }}
    repository: fagai/${{ env.IMAGE_NAME }}
    tags: ${{ env.IMAGE_VERSION }}

build-push-actionの例ではpasswordを設定するようになっていましたが、Docker Hubにもaccess tokenがあるのでそっちを設定してからつけました。

https://docs.docker.com/docker-hub/access-tokens/

キャッシュとか色々ちゃんとしたい

現状のままではキャッシュを参考にしてくれません。(ただ、2回目のbuild-push-actionはcacheを元にしてくれるので片方でbuild+pushしてしまえばもう片方はすぐにpush出来ます)

build-push-actioncache_fromsというパラメータがあるのでこれをうまく使いたいです。

色々試していく結果、cache_fromsを利用するためにはBuildkitを使う必要があることがわかりました。
また、build_args: BUILDKIT_INLINE_CACHE=1をセットしないといけないことも判明。
どうやらcache_fromsはドメイン部分も指定しないとダメっぽい雰囲気でした。←ここ結構悩んだ

ということでこんな感じになりました。

- name: Push to GitHub Packages
  uses: docker/build-push-action@v1
  env:
    DOCKER_BUILDKIT: 1
  with:
    dockerfile: ${{ matrix.images }}/Dockerfile
    username: ${{ github.actor }}
    password: ${{ secrets.CR_PAT }}
    registry: docker.pkg.github.com
    repository: fagai/docker-php/${{ env.IMAGE_NAME }}
    tags: ${{ env.IMAGE_VERSION }}
    build_args: BUILDKIT_INLINE_CACHE=1
    cache_froms: docker.pkg.github.com/fagai/docker-php/${{ env.IMAGE_NAME }}:${{ env.IMAGE_VERSION }}

これで行ける!と思ったのですが

キャッシュされてない・・・となりまして、Actionsのほうを見てみると

#4 importing cache manifest from docker.pkg.github.com/fagai/docker-php/php...
#4 ERROR: httpReaderSeeker: failed open: could not fetch content descriptor sha256:65d9f276544048f140bb1a1cceea52f86e7e704b351c56b8d6b9f18c5e9c0e4d (application/vnd.docker.distribution.manifest.v2+json) from remote: not found

こんな感じでエラーが出てキャッシュが取得できずにそのままビルドが走ってしまっていました。
どうやらGitHub Package Registryのほうはdockerの新しいmanifestにまだ対応してないようです。(GitHub Container Registryのほうは対応している様子)

https://github.community/t/handle-multi-arch-docker-images-on-github-package-registry/14314

ということで、先にdocker Hubの方からビルドすることにしました。
cache_fromsはdocker.ioから書かないとダメです。

- name: Push to Docker Hub
  uses: docker/build-push-action@v1
  env:
    DOCKER_BUILDKIT: 1
  with:
    dockerfile: ${{ matrix.images }}/Dockerfile
    username: ${{ github.actor }}
    password: ${{ secrets.DOCKER_HUB_TOKEN }}
    repository: fagai/${{ env.IMAGE_NAME }}
    tags: ${{ env.IMAGE_VERSION }}
    build_args: BUILDKIT_INLINE_CACHE=1
    cache_froms: docker.io/fagai/${{ env.IMAGE_NAME }}:${{ env.IMAGE_VERSION }}

ということでこんな感じになります。

#4 importing cache manifest from docker.io/fagai/php:7.2-alpine-fpm
#4 DONE 0.2s

その後の処理もCACHEDという表示がされ、ビルドが動かずにキャッシュをベースにしていることがわかります。

その後の後付け

- name: cancel old workflow
  uses: styfle/cancel-workflow-action@0.4.1
  with:
    access_token: ${{ github.token }}

これは過去にやったことがありました。過去のActionをキャンセルしてくれるActionです。
何度もcommitしたときに過去のActionがずっと残って動いてしまうことを解決してくれます。

また、scheduleもセットしまして、毎週月曜日にActionが動くようにしました。

on:
  push:
    branches:
      - master
  pull_request:
  # 定期更新をやる(毎週月曜日)
  schedule:
    - cron:  '0 0 * * 1'

最後に

GitHub Actionsにbuildとpushをするようにした結果、Docker HubがずっとQueueで待ちになる問題も解決されたし、何より並列でビルドができるので短時間でpushするように出来ました。

build-push-actionはv2でbuildxというDocker 19.03で新しく追加されたビルドが利用されるようになるみたいです。
BuildKitは半公式みたいな感じでBuildxが公式のマルチCPUビルド対応の機能みたいです。
macとかではdocker buildx installと打つことでdocker buildへのエイリアスが貼られて勝手にbuildxを使ってくれるようになります。いいね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneクローン? OSSWebDBのExmentをLightsail+Dockerで立ち上げたら結構ハマったのでメモしておく

Exment is 何?

2020-09-08_11h46_18.png
Exmentは、Laravel製(ということは、LAMPですね)のWeb DBシステムです。リレーショナルなデータベースをGUI管理画面から操作できます。

ExmentはOSSで、GPLライセンスです。開発は株式会社カジトリ​が中心となって行っています。詳細は開発者の方の記事をご覧ください

GUIのWeb DBというと、なんとなくサイボウズ社のkintoneを連想する方もいるのではないでしょうか。

開発元からはキントーンのキの字も聞こえてきませんが、筆者はひそかにkintoneクローンだと思っていて、かなり可能性を秘めているOSSプロダクトだと考えています。

正直、かなりほれ込んでいるのですが、この記事ではお気に入りポイントは解説しません。また別の機会に。

クラウドでなるべくお安くExmentを運用したい!

ローカルでは、Dockerを使ってExmentを試すことができます。作ってくれた人ありがとう!

ローカルで実際やってみたところ(macOS Mojave、Windows 10 Home WSL2で確認)、あっさり出来ました。すごいですね。

そうしたら、クラウドでホスティングして、外出先などからもアクセスしたくなるというのが人情ですよね。

ホスティング先をいろいろ考えてみました。フロントエンドだけなら、NetlifyやVercelといった無料のサービスもあるのですが、残念ながらこれはバックエンドのシステムです…

先述していますが、Exmentはレンタルサーバーでも運用できます。

Exment公式サイトには、さくらやエックスサーバーといったレンサバでのインストール手順が公開されていますが、残念ながら、さくらやエックスサーバーのアカウントを私は持ち合わせておりません。つまり、筆者はレンサバの契約をしていないのですね。(フロント寄りの作りかけ個人プロダクトがNetlifyやVercelにはわんさかあるんですけど)

Exmentのためだけにレンサバ借りるのもなんだかなあ、だったらVPSのほうが良くない? と色々調べた結果、AmazonのLightsailが私の用途にぴったりだと気付きました。

(なお、筆者はこの時点でVPS、AWS童貞です)

ではさっそくLightsailのアカウントを取得して、始めるぞ!

Lightsailにログインしてからインスタンスの作成あたりまでは、下記記事が詳しいです。

今回は、一番安い$3.5/月の512MBRAMのインスタンスにしました。なるべくお安く、というテーマなので。どうしてもスペック足りなかったら、その時にスケールアップなりなんなり対応を考えようというスタンスです。

Lightsailには、WordPressなどのWebアプリケーションがセットになったインスタンスひな形があるのですが、当然知名度まだまだのExmentひな形というのはありません。

そこで、OSのみのインスタンスを選択します。今回は、CentoOS7を選択しました。

CentOSにフツーにインストールする? それとも…?

Exment公式には、CentOS7にインストールする手順も公開されており、またそれを補強する記事もあります。(下記参照)

が、公式を見ていただければわかる通り、結構な手順があります。で、実際1度やりました。何度か環境を捨てたりやり直したりする過程で「この手順毎回やってられんわ!」となり、他の方法を考えることに至ります。

せや、Dockerそのまま載せたったらええやん?

Lightsail+DockerでExmentを動かす(httpsもあるよ!)

ここからは、ハマりポイントを踏まえた回避策も含めて手順を記します。ここを守れば、最短でExment on Lightsail+Dockerが実現できます。

CentOS7でインスタンス作成後、Docker、Docker-composeとgitをインストールする

では、もろもろインストールしていきます。

毎回、sudo つけるの大変なので、rootになります。

Lightsailでrootになるには、こちらの記事を参考にしました。

$ sudo su -

Dockerをインストールします。こちらの記事が詳しいです。

[root@ip-172-xx-xx-x ~]# yum install -y docker          # dockerのインストール
[root@ip-172-xx-xx-x ~]# service docker start           # dockerの起動
[root@ip-172-xx-xx-x ~]# groupadd docker                # ユーザー権限で実行できるようにしておく
[root@ip-172-xx-xx-x ~]# usermod -g docker centos       # 作成したグループにcentosユーザを追加
[root@ip-172-xx-xx-x ~]# sudo /bin/systemctl restart docker.service
[root@ip-172-xx-xx-x ~]# docker info        

これでDockerはインストールできました。
続いて、Docker-composeです。

[root@ip-172-xx-xx-x ~]# curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
[root@ip-172-xx-xx-x ~]# chmod +x /usr/local/bin/docker-compose
[root@ip-172-xx-xx-x ~]# docker-compose --version

最後に、Gitをインストールします。CentOS7のyumで入るGitは、1.8.2と古いバージョンのものです。気になる人は、下記記事を参考に新しいのを入れてみてください。今回は、git cloneしたいだけなので、そのままyumでインストールします。

[root@ip-172-xx-xx-x ~]# yum install -y git

これで、Gitもインストールできました。

スワップ領域を作る

RAM512MBのインスタンスなので、DockerでMySQLまで動かすとメモリ不足になりました。(ハマりポイント1)なので、先んじてスワップ領域を作っておきましょう。

スワップの作り方は下記記事を参考にしました。

[root@ip-172-xx-xx-x ~]# dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress

コマンドの書き方をミスってたため、結構ハマりました(ハマりポイント2)

あれこれ試行錯誤した過程で、/dev/zeroが何のファイルかわかっておらず、rm -rfしちゃったのはいい思い出です。

/dev/zeroを復活させるのは、こちらの記事を参考にしました。

[root@ip-172-xx-xx-x ~]# mknod -m 666 /dev/zero c 1 5
[root@ip-172-xx-xx-x ~]# chown root:mem /dev/zero

status=progressオプションですが、今回はスワップ領域が4Gと大きめなので、しばらくターミナルが沈黙しちゃうと心配です。なので、ddコマンドの進捗をお知らせしてくれるオプションをつけました。下記記事を参考にしています。

ddでスワップ領域が作成されたら、粛々と残りの作業を進めます。

[root@ip-172-xx-xx-x ~]# chmod 600 /swapfile #パーミッションの変更
[root@ip-172-xx-xx-x ~]# mkswap /swapfile #スワップの作成
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=d0519bf6-8abf-4c0d-9375-8068c9e5e9a1
[root@ip-172-xx-xx-x ~]# swapon /swapfile #スワップの有効化
[root@ip-172-xx-xx-x ~]# free -m #スワップの確認

最後に、スワップの永続化をします。
viで/etc/fstabを開き、

/swapfile                                 swap                    swap    defaults        0 0

でおしまいです。

git cloneで、docker-compose.ymlとDockerfileを拾ってくる。

先述ご紹介した、ExmentのDockerを作ってくれた方のGithubから拾います

[root@ip-172-xx-xx-x /home/centos/]# git clone https://github.com/yamada28go/docker-exment.git

場所はどこでもいいと思うんですけど、デフォルトユーザーディレクトリ直下にしました。

httpsは?

Dockerでhttpsというと、https-portalが有名なようです。

結論から先にいうと、https-portalを先に設定した状態でExmentをインストールしたら、上手くいきませんでした!!!(ハマりポイント3)

なので、SSLを設定する前に非SSLの状態でExmentのインストールを進めます。

一応、docker-compose.ymlに目を通しておきますか。

docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - www-data:/var/www
    depends_on:
      - php

  php:
    build: ./php
    volumes:
      - www-data:/var/www
    depends_on:
      - db

  db:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: exment_database
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_USER: exment_user
      MYSQL_PASSWORD: secret

  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8888:80
    depends_on:
      - db

# volumes を定義する
volumes:
  # volume の名前を指定
  # Exmentのインストールパス
  www-data:
    # Compose の外ですでに作成済みの volume を指定する場合は ture を設定する。
    # そうすると、 docker-compose up 時に Compose は volume を作成しようとしません。
    # かつ、指定した volume が存在しないとエラーを raise します。
    #external: true
  # mysql dbのインストールパス
  mysql-data:

あとでhttps-portalが80番ポートを使うので、nginxが8080になっているのは逆に都合がいいです。特にこのまま何も編集しません。

docker-compose.ymlとDockerfileは何もさわりませんが、php.iniだけは1行だけ追記します。

最後の行に

memory_limit=-1

を追記しておきます(ハマりポイント4、詳細は後述)

ではいよいよ…

[root@ip-172-xx-xx-x /home/centos/]# docker-compose up -d

初回なので、イメージの取得とビルド、ボリュームの作成をやってくれます。

起動が完了したら、docker-comopse psで、全コンテナがUpしていることを確認します。(スワップを作っていなかった時は、ここでMySQLがExitしてました)

無事起動したら、IPアドレスでアクセスしてみよう

Lightsail側で以下の手順を済ませておきます。

  • 静的IPのアタッチ
  • ポート8080番の開放

xx.xx.xx.xx:8080にブラウザでアクセスしてみて、Laravelの初期画面が表示されていれば成功です。

xx.xx.xx.xx:8080/adminにアクセスすると、Exmentの初期設定画面になります。

画面は3部構成になっていて、

  1. 言語とタイムゾーンの指定
  2. DB設定
  3. DB設定開始ボタン

の3画面です。何か入力するのは2画面目のDB設定です。

Dockerを使っていますので「ExmentのDocker環境を作ってみた」の記事を参考に、設定を埋めます。

  • ホスト名 → db
  • データベース名 → exment_database
  • ユーザー名 → exment_user
  • パスワード → secret

この後、無事インストールが完了すれば、Exmentの初期画面となります。

添付ファイルとかはS3に保存したいじゃんね!

今回のLightsailインスタンスは、保存領域が20GBと、まあ何か動かすのはいいけど、バイナリデータ突っ込んでいったらすぐパンパンになるよね、って容量です。

Exmentには、外部のストレージサービスに各種ファイルを保存するオプションがあります。

せっかくですので、AWSでそろえて、S3に保存させるようにしてみましょう。

S3も童貞でしたので、下記記事を参考にバケットを作成してみました。

Exment側でも設定が必要です。既にdocker-compose exec php bashで立ち上がっているコンテナの中に入ります。

[root@ip-172-xx-xx-x /home/centos/]# docker-compose exec php bash

これで、Exmentが動いているphpコンテナの中に入れます。プロンプトの表示がこんな感じに変われば成功です。

root@f54bef27801a:/var/www#

つまり、クラウド上にあるLightsailの中にあるDockerコンテナphpの中にいるという二重構造なわけですね。

引き続き、「(上級者向け)ファイルの保存先変更」を読み解きながら、Exment(Laravel)のファイルを修正していきます。

Exmentルートフォルダにある、.envファイルをvimで修正/追記します。

EXMENT_DRIVER_EXMENT=s3
EXMENT_DRIVER_BACKUP=s3
EXMENT_DRIVER_TEMPLATE=s3
EXMENT_DRIVER_PLUGIN=s3

AWS_ACCESS_KEY_ID=(AWS S3のアクセスキー)
AWS_SECRET_ACCESS_KEY=(AWS S3のシークレットアクセスキー)
AWS_DEFAULT_REGION=(AWS S3のリージョン)

AWS_BUCKET_EXMENT=(添付ファイルで使用するAWS S3のバケット)
AWS_BUCKET_BACKUP=(バックアップで使用するAWS S3のバケット)
AWS_BUCKET_TEMPLATE=(テンプレートで使用するAWS S3のバケット)
AWS_BUCKET_PLUGIN=(プラグインで使用するAWS S3のバケット)

なお、EXMENT_DRIVER_xxxはすべて設定する必要はなく、必要があるものだけ設定します。それに紐づくAWS_BUCKET_xxxも必要なものだけでOKです。

私は添付ファイルとバックアップデータはS3に保存したかったので、

  • EXMENT_DRIVER_EXMENT
  • EXMENT_DRIVER_BACKUP
  • AWS_BUCKET_EXMENT
  • AWS_BUCKET_BACKUP

の4つのみ設定しました。

最後に、composerでライブラリをインストールします。

先ほど、docker-compose up -dの前にphp.iniを編集しましたが、Composerはメモリ食いで、すぐPHPのメモリ利用可能上限に達してしまうので、この上限を解除する設定をしたのでした。

Composerはインストールに時間がかかるので、時間かかった結果失敗した、って辛いですよね…(筆者はとても悲しかったです。)なので、この設定はcomposer requireをする前にもう一度確認しておきましょう。

root@f54bef27801a:/var/www# php -i | grep memory_limit
memory_limit => -1 => -1

-1になっていればOKです。(メモリ上限なし、の意味)

では、いよいよライブラリのインストールです

root@f54bef27801a:/var/www# composer require league/flysystem-aws-s3-v3 ~1.0 -vvv

-vvvオプションは、もっとも粒度細かくログを出す、という意味の指示です。composerはインストールにとても時間がかかるので、長い時間ターミナルが沈黙していると心配になります。

なので、逐次ログを出してくれるようにします。このオプションをして長いこと沈黙があれば、それは本当に何かしらの理由で止まっているか、めちゃくちゃ重い処理をしている、ということになります…

S3に添付ファイルをアップするオプションの設定は以上です。適当な画像でもアップして、バケットの中にファイルがあることを確認しましょう。

最後に呪いのhttpsです…

いや、httpsに何の悪いところもないのですが、かなりハマって悩まされたので…

色々やり方が悪かったのかと思い、Docker環境全捨てからの再インストールを何度も行ったので、かなり時間を食ってしまいました。

さっきも言いましたが、docker-composeにhttps-portalも混ぜて書いてしまうと、初回インストールに失敗します。結局はよくわからんエラーに遭遇して詰みました。

インストールは3画面あるといいましたが、最後の3画面目のインストールボタンを押したら、あのLaravelのグレーみの強いエラー画面で

Use of undefined constant STDIN - assumed 'STDIN' (this will throw an Error in a future version of PHP)

って出てきて、DBにデータが差し込めないことに。PHPやLaravelに明るくない筆者であるため、ここで断念しました。

httpならちゃんとうまくいったので、結局このエラーをつぶすことはあきらめ、httpでインストール完了させ、その後httpsにするという作戦に切り替えた次第です。

https-portalをdocker-compose.ymlに追記する

https-portalの部分だけ書き出します。

docker-compose.yml
https-portal:
  image: steveltn/https-portal:1
  ports:
    - '80:80'
    - '443:443'
  links:
    - nginx
  restart: always
  volumes:
    - ./certs:/var/lib/https-portal
  environment:
    STAGE: 'production'
    DOMAINS: >-
      example.com -> http://nginx:8080
  depends_on:
    - php

特に難しいことはありません。公式のサンプルとそんなに変わりませんし。ポイントとしては、enviroment:STAGE:が、'production''staging'でないと、Let's Encryptの本チャンの証明書はもらえないということです。ここがlocalとか指定なしだと、ローカル開発ってことで、なんちゃって証明書が発行されます。ここも地味にハマりポイントでした(ハマりポイント5)

さて、最後に https://example.com/ にアクセスして、Laravelの初期画面が表示されれば晴れて成功です…

と言いたいのですが、まだあります。

https://example.com/admin にアクセスすると、盛大に画面崩れを起こしているじゃないですか!

ブラウザコンソールを見ると、mixed contentでhttpがソースのCSS/JS類が全部ブロッキングされています。

これの対処が最初全然わからなかったのですが、試行錯誤の結果、LaravelおよびLaravel-adminが犯人と断定されました! asset('/css/hoge.css')みたいな記述のところで、http付のパスを出力しちゃってるようです…

以下、この件についての対策です。またdocker-compose exec php bashして中に入ってください。

/var/www/exment/.env
APP_ENV=production
/var/www/exment/app/Providers/AppProvider.php
class AppServiceProvider extends ServiceProvider
    public function boot()
    {
    if (config('app.env') === 'production') {
       \URL::forceScheme('https'); //Schemaじゃなくて、Scheme!!!(ハマりポイント6)
    }
    }
/var/www/exment/config/admin.php
    /*
    |--------------------------------------------------------------------------
    | Access via `https`
    |--------------------------------------------------------------------------
    |
    | If your page is going to be accessed via https, set it to `true`.
    |
    */
    'https' => env('ADMIN_HTTPS', true), // ←デフォはfalseなので、trueに!

これで、すべてのアセットがhttpsから配信され画面崩れなく表示されるようになりました。

正直、これが本当の意味で正解かどうかわかりません。もしかしたら、AppProvider.phpは不要かもしれません… Laravelのバージョンによってコードの書き方が微妙に違うようでした。これは、本当にたくさんの参考ソースを読みまくって、なんとか動くコードに落ち着いたというのが実情です。

もし、もっと良い方法があるよ、という方はぜひコメント欄で教えてください。

以上、無事動くようになりました!

今のところ、機嫌よく動いてくれています。

セキュリティ等

本記事は検証目的の環境づくりのため、セキュリティ等については触れておりません。詳しい方は補足いただけると助かります。

今後

Exmentの素敵なところをほめまくる記事とか書きたいですね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Postgresql超初心者が知っておくべきこと

超初心者向けPostgresql入門

IT全般に関する知識が皆無の文系大学生がインターンシップで初めてPostgresqlを触り、少し苦労したので、知っておくべき基礎中の基礎をご紹介したいと思います。
Postgresqlを初めて触るときに、こういう記事があればよかったなという記事にしたいと思いますので何卒よろしくお願いします。

深い理解というよりは、Postgresqlがざっくりどんな感じのものかということを理解するためにこの記事を読んでいただけるとありがたいです。

ちなみに著者のパソコンはMacbookですので、基本的には
MacbookユーザーのPostgresql超初心者向けの記事となっております。

Postgresqlとは何ぞや

PostgreSQL(ポストグレスキューエル)はオープンソースのリレーショナルデータベース管理システム(RDBMS)です。

Codezine「Postgresqlとは?」より引用
https://codezine.jp/article/detail/11753

簡単に言いますと、データがたくさん入っているところから欲しいデータがどこにあるのかを調べることができるものです。

さらにわかりやすく例を使いますと、家(データベース)自室(スキーマ)の中の洋服タンス(テーブル)の中に欲しい服(データ)があるかを調べられるものです。それだけでなく、どこに何が置いてあるかわからないという家を整理整頓してくれるものです。

部屋の整理が苦手な方なら、朝起きて急いで家を出たい時に着たい服が見つからないということもよくあるでしょうから、このPostgresqlが便利であるということはお分かりになるでしょう。

Postgresqlを始める前に準備すること

はじめにHomebrewDockerをインストールして、ターミナルでPostgresqlを開いてください。
インターン2日目にこの指示を受けた私は脳がパンクしました。

順に説明していきます。

ターミナルとは何ぞや

簡単に言いますと、パソコンに命令する場所です
ホーム画面でcommand + spaceでSpotlight検索ができますので「ターミナル」と打ってください。
スクリーンショット 2020-09-08 14.49.08.png
ハッカーみたいなカッコいい画面が出てきます。
これがターミナルです。
Postgresqlを使用する際は基本的にここで作業をすることになります。

ちなみに
Postgresqlを開いた状態のコマンドと、ターミナルでのコマンドは違うので要注意!

Posgresqlに入れている場合は
データベース名=#
入れていない場合は上画面のように
フォルダ名$
のようになっていますのでわかると思います。

Homebrewとは何ぞや

Homebrewとは、Mac OSにおいて、プログラミング上必要となってくる
パッケージをインストールしたりアンインストールしたり出来るシステムです。
このようなものをパッケージ管理システムと呼びます。
つまり、Homebrewを使えば、便利なアイテムのダウンロードが非常に簡単になってきます。

プログラミング入門者のための「Homebrew」インストールより引用
https://qiita.com/Naggi-Goishi/items/391b374305bc41b0d9f3

わかりやすい説明を引用させていただきました。
今回ではDockerなどのパッケージをインストールするのに便利なものだということです。

Homebrewのインストール

Homebrewのホームページを開くと
https://brew.sh/index_ja

スクリーンショット 2020-09-08 16.44.23.png

という風になっており、「Install Homebrew」の下にあるコマンドをターミナルにコピペするとインストールできます。

Dockerとは何ぞや

Docker(ドッカー)は、コンテナ仮想化を用いてアプリケーションを開発・配置・実行するためのオープンソースソフトウェアあるいはオープンプラットフォームである

Wikipedia「Docker」より引用
https://ja.wikipedia.org/wiki/Docker

初心者には難しく、私も概念を完全に理解できているわけではありませんが、仮想環境を作ることでPostgresqlなどをサクサク実行できるということです。

Dockerのインストール

Docker公式サイトからDockerのアカウントを作り、Dockerをインストールしてください。
https://hub.docker.com/editions/community/docker-ce-desktop-mac

右上のところにクジラのマークが表示されれば成功です。

Postgresqlを開こう

無事DockerHomebrewがインストールできた後はいよいよPostgresqlを開きます。
1.まずターミナルを開いて
docker login
と打ち込み、Dockerにログインします。
2.
docker pull postgres
でpostgresqlをインストールします。
3.
docker run --name dev-dash-postgres -e POSTGRES_USER=ユーザー名 -e POSTGRES_PASSWORD=パスワード -p ポート名(初期値だと5432:5432) -d postgres
でDockerを起動します。
4.
psql -h localhost -U ユーザー名
でPostgresqlに接続します。

ユーザー名、パスワード、ポート名は自身のものを打ち込んでください。

Dockerがインストールされていなかったりすると実行できないこともあるので注意です。

さあPostgresqlを始めよう

これからより実用的な話に入る前に、Postgresqlの基本原則をお伝えします。
文章を書いたあとには基本的に「;」を絶対につけてください。これなしでは反応しません。
初歩的すぎるからなのかわかりませんが、これを教えてくれる記事が少なかった、、、。気をつけてください。

それではこれから
初歩的なコマンド
CREATE TABLE
SELECT
INSERT
を紹介していきます。

Postgres覚えておくべき用語

家を例に説明します。

データベース=。色んなものが入っている場所。
スキーマ=部屋。自室、倉庫など。データベースよりも小さな括り。
テーブル=タンス。洋服が入っている場所など。スキーマよりも小さな括り。
カラム=タンスの引き出し。下着が入っている引き出しなど。テーブルよりも小さな括り。
データ=洋服。特定の下着、特定のシャツ。

CREATE TABLE

用語を理解するのに最適な「CREATE TABLE」(テーブルを作る)というコマンドを説明いたします。

Begginer.sql
CREATE TABLE souko.tansu{スキーマ名.テーブル名} (pants varchar, shirts varchar);{カラム名+データ型}

下記のように打ち込みます。

スクリーンショット 2020-09-08 14.25.36.png

この文頭のbeginner=#のbeginnerがデータベース(家)です。
souko(スキーマ)tansuというテーブルを作るという形です。
pants,shirts(タンスの引き出し)というカラムをテーブルの中に作ります。

この後のSELECTINSERTでさらに理解を深めていきましょう。

SELECT

Postgresqlで一番使うことになるコマンド「SELECT」をご紹介します。
簡単に言うと「検索」です。
テーブルの中にあるデータを検索したいときに使います。

Begginer.sql
SELECT * FROM (スキーマ名.)テーブル名;

ここのアスタリスクは全てを意味します。指定したテーブルの中にあるデータの全てを出したいときには「*」を使用します。

全てではなく、特定のものだけを検索したいときには、カラム名(引き出し)をSELECTの後に入れます。

これもわかりやすく、先ほどの家を例に出しますと、

Begginer.sql
SELECT pants FROM souko.tansu;

といった形です。

この例えですと、「自分で部屋の中ひっくり返したらすぐ見つかるじゃないか」と思う方がいらっしゃるかもしれませんが、データベースというのは数億件のデータを管理したりもするものです。

数億の服が散らばった部屋の中から欲しい服を取り出すのは、無理です。

INSERT

これもめちゃ使うことになるコマンド「INSERT」。
簡単にいうと「タンスに服入れる(テーブルにデータを入れる)」です。

Begginer.sql
INSERT INTO (スキーマ名.)テーブル名(カラム名,カラム名,、、、) values(データ1,データ2,、、、);

これを家の例で例えると

Begginer.sql
INSERT INTO souko.tansu(pants, shirts) values('red_pants', 'red_shirts');

という風になります。
これはパンツを入れる引き出しに赤のパンツを入れ、シャツを入れる引き出しに赤のシャツを入れるという意味です。

同じくblue_pants,blue_shirtsを入れて、tansu内の全てをSELECTをするとこのようになります。

スクリーンショット 2020-09-08 18.23.46.png

パンツの引き出しだけを見たい時は

Begginer.sql
SELECT pants FROM souko.tansu;

と打ち込みます。すると

スクリーンショット 2020-09-08 18.26.20.png

と出て何のパンツが入っているかを見ることができます。

エラーが出たとき

エラーが出たときはエラーの文言を読んでみて、それでもわからなかった時には文言をコピペしてGoogleで調べましょう。
ただ超初心者だとそれでもよくわからないことの方が多いと思います。そういう時は、どこかしらにエラーがあるのでじっくりと全てを見直していきましょう。
とはいえ、、、。

初心者にエラーは地獄

エラーのキツいポイントとして、文言がミスを正しく指摘してくれているわけではないということです。
あくまで例ですが、
Error:そのタンスの中に服無いよ
というエラーが出ているにも関わらず、そのタンス(テーブル)に服(データ)が入っているということがあります。そのような場合は、タンスの場所であったり、タンスを作るときに何かしらのミスが発生しているなどの問題があり、初心者は理解できないことの方が多いです。
私は一つのエラーを調べるのに1日かかったことがあります。(先輩に聞いたら2分で解決してくれました、、、。)
初心者のうちは自分で調べることも大事ですが、本当にわからないときは先輩に聞くというのが、自分にとっても会社にとっても良いと思います。

初心者あるあるのミス

セミコロン忘れ

文末に「;」を入れるのを忘れているというのは初心者にはよくあるミスだと思います。
コマンド打ち込んだのに何も実行されない、、、。という場合はとりあえずセミコロンが付いているかどうかを確認してください。

パソコン再起動したらPostgres入れないなぜ、、、

パソコンを一度シャットダウンするとDockerから抜けてしまいます。
この場合にはDockerを再起動する必要があります。
Docker start コンテナ名
コンテナ名がわからない場合は
Docker ps -a
で調べられます。

まとめ

初心者系の記事でも説明を省いている記事も多いので、超初心者向けとして必要以上にたくさん書きました。
超初心者のほとんどは何となく難しそうだなという印象を抱いていると思いますが、一週間くらいである程度慣れてくると思うので毛嫌いせずに頑張ってください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud Buildのステップ内でDockerを使うならcloudbuildネットワークを覚えておく

概要

Cloud Buildで

  • ステップ内でDockerを使い
  • DockerからApplication Default Credentialも使いたい

なら --network=cloudbuild を渡そうという話です。

前提

例にはberglas利用します。
berglasは環境変数に特定フォーマットで秘密情報への参照を入れておくと、その値をとってきてくれます。
例えば FOO=sm://$PROJECT_ID/$SECRET_NAME berglas exec -- bar を実行すると、Secret Managerから取ってきた値が環境変数 FOO に入って bar が実行されます。

準備

まずSecret Managerで TEST というシークレットに値を入れておきます。

$  echo -n "supersecret" | gcloud beta secrets create TEST --replication-policy automatic --data-file=-

またCloud Buildの実行サービスアカウントに、Secret Accesorロールをつけておきます。

$ gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:$(gcloud projects describe $PROJECT_ID --format 'value(projectNumber)')@cloudbuild.gserviceaccount.com" \
  --role roles/secretmanager.secretAccessor

実験

実験を単純にする為に env で環境変数を出力していますが、ログに残るので本当に秘密の情報を扱うならそのまま使わないように気をつけてください。

ステップ内部でDockerを使わないのでうまくいく例

まずberglasのイメージを直接使ってみます。

cloudbuild.yaml
steps:
  - name: 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
    args:
      - 'exec'
      - '--'
      - 'env'
    env:
      - 'TEST=sm://$PROJECT_ID/TEST'

これで実行してみます。

$ gcloud builds submit --config cloudbuild.yaml --no-source
...
TEST=supersecret
...

復元されたTESTをみることができました。

ダメな例

次にビルドステップ内でdocker run経由でberglasを使ってみます。

cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'run'
      - '-e'
      - 'TEST=sm://$PROJECT_ID/TEST'
      - 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
      - 'exec'
      - '--'
      - 'env'

すると…

$ gcloud builds submit --config cloudbuild.yaml --no-source
...
failed to access secret sm://$PROJECT_ID/TEST: failed to access secret: rpc error: code = Unauthenticated desc = transport: Get "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform": dial tcp 169.254.169.254:80: i/o timeout
...

エラーが起きてしまいます。DockerコンテナからApplication Default Credential取得リクエストができないようですね。

どんなネットワークがあるのか試しに見てみます。

cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'network'
      - 'ls'
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
NETWORK ID          NAME                DRIVER              SCOPE
ed09d11c5bd1        bridge              bridge              local
a01cfc17c577        cloudbuild          bridge              local
f3426b77657b        host                host                local
9b756bf55527        none                null                local
...

Application Default Credentialを使いたい場合には、このうち cloudbuild ネットワークを渡す必要があります。( host ではだめです。)
これはドキュメントにも書いてあります

うまくいく例

cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'run'
      - '--network=cloudbuild' # 追加
      - '-e'
      - 'TEST=sm://$PROJECT_ID/TEST'
      - 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
      - 'exec'
      - '--'
      - 'env'
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
TEST=supersecret
...

無事見ることができました。

結論

Cloud Buildのステップ内部でDockerコンテナを使い、コンテナからApplication Default Credentialも使いたいなら --network=cloudbuild を渡しましょう。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む