- 投稿日:2020-09-16T23:59:55+09:00
マルチステージによるDockerイメージの軽量化-Reactアプリ編
はじめに
はじめまして、最近Docker、Kubernetes辺りをいじるのにハマっております。
今回はDockerイメージの軽量化に挑戦してみました!今回は create-react-app コマンドを用いてデフォルトで作成したものをコンテナ化しております。
- 事前準備
- create-react-appでアプリ作成
// アプリ作成 $ create-react-app sample-react-app $ cd sample-react-app問題のDockerfile
Dockerfileを準備します。流れとしては
- production用にbuild
- 静的ファイルを実行するモジュールをインストール、実行という感じです。
DockerfileFROM node:12 COPY . /react-app WORKDIR /react-app RUN npm install && npm run build && npm install -g serve CMD ["serve","-s","build" ]これでデフォルトだと5000番でListenするので以下のようにポートフォワードして実行すれば localhost:5000 でアプリが動くことが確認できると思います。
$ docker run -p 5000:5000 sample-react-app:0.0.1昨日までの私はおー!Reactアプリコンテナ化できたじゃんと満足していました。
けど思いました。最終的に静的ファイル実行するだけなんだからnodeの環境要らなくない?
ちなみにここでDockerイメージのサイズを見てみると...
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE sample-react-app 0.0.1 6e7bc9096dd7 9 minutes ago 1.31GB...でかいっす。
ただ、gitにproductionのファイル群をあげたりはそんなにしないかなと思うので、CIツールとか使ってgitのリポジトリからビルドしていくならnpm install, npm run buildはDockerでビルドしていく段階で欲しいと思うのです。
そこでマルチステージ!これがあるじゃん。
ということでマルチステージを使ってproductionのファイル群をnginxの方に持っていく、というのをやってみました。
改良Dockerfile
改良Dokerfile#第一段階(productionファイル生成まで) FROM node:12 as node COPY . /react-app WORKDIR /react-app RUN npm install && npm run build #第二段階(一段階目のコンテナの中身から静的ファイル群だけをコピーする) FROM nginx:1.19.2-alpine COPY --from=node ./react-app/build /usr/share/nginx/html CMD nginx -g "daemon off;"ドキドキの起動です。。。タグを0.0.2にしてビルド、実行してみます
$ docker build -t sample-react-app:0.0.2 . $ docker run -p 5000:80 sample-react-app:0.0.2そしてサイズは...
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE sample-react-app 0.0.2 9148ac06ddbe 3 minutes ago 22.5MBかなりスマートになりました!サイズだけなら1/60になりました!
おわりに
個人的にここまで劇的に変えられたと結構な達成感を持てました!
今後はコンテナ化だけで満足せず、どのように作っていくかもじっくり考えてみたいと思います。
- 投稿日:2020-09-16T23:34:23+09:00
k8sのマニフェストでPodのdocker imageのCMDを書き換えるときはcommandじゃダメ
ちゃんとドキュメントを読めば書いてありました。
ただ、間違えやすそうなのでメモ。
- ちゃんと読むべきもの
結論
- マニフェストのcommandはDockerfileのENTRYPOINT
- マニフェストのargsはDockerfileのCMD
apiVersion: v1 kind: Pod metadata: name: command-demo labels: purpose: demonstrate-command spec: containers: - name: command-demo-container image: debian command: ["printenv"] # こっちはENTRYPOINT args: ["HOSTNAME", "KUBERNETES_PORT"] # こっちはCMD restartPolicy: OnFailure注意
また、command・argsをそれぞれ定義したかどうかで挙動が変わるので注意。
Dockerfileが
- ENTRYPOINT: echo
- CMD: HOSTNAME
だった場合
command args 実行されるコマンド 未定義 未定義 echo HOSTNAME printenv 未定義 printenv 未定義 KUBERNETES_PORT echo KUBERNETES_PORT printenv KUBERNETES_PORT printenv KUBERNETES_PORT となる。
- 投稿日:2020-09-16T21:56:30+09:00
Docker Hub代わりのGitHub Container Registry入門
概要
Docker Hubの無料枠に制限がかかるという話もあり、GitHub Container Registryの使い方を調べたのでメモする。具体的には以下を実現したい。
- GitHubへpushする度、GitHub Actionsでdockerイメージをbuildし、GitHub Container Registryにpush
- その際、GitHubへpushしたタグに応じて、dockerイメージのタグも変更する
環境
- wsl2のDebian
- Docker version 19.03.12, build 48a66213fe
事前準備
GitHub Container Registryに自動でdockerイメージをpushするには、Personal Access Tokenが必要1。GitHub右上の自分のアイコンから
Settings
>Developer settings
>Personal access tokens
>Generate new token
の手順で作成する。スコープは以下の画像のもので大丈夫そう。
得られたトークンはDockerfileなどを管理しているGitHubリポジトリで
Setting
>Secrets
>New secret
の手順で登録しておく(ここではCR_PAT
という名前で保存したことにする)。YAMLファイル作成①
GitHub Actionsを制御するためのYAMLファイルを作成する。以下のようなディレクトリ構成を想定2。
. ├── .git ├── .github │ └── workflows │ └── build_on_push.yaml └── Dockerfile
build_on_push.yaml
の内容は以下の通り。name: Publish Docker image on: push jobs: main: name: Push Docker image to Docker Hub runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} - name: Push to GitHub Container Registry uses: docker/build-push-action@v2 with: push: true tags: ghcr.io/dr666m1/qiita_starwars:latest
name:
はworkflowやjobを命名しているだけなので任意の値。on:
ではトリガーとなるイベントを指定(ここではpush)。3行目のjobs:
で5つのstepからなるjobを定義しているので、以降で各stepについて簡単に解説する(ちなみにruns-on:
はjobを実行する仮想マシンの指定で、ここではGitHubホストランナーを選択している)。Checkout
actions/checkout@v2
というactionで、GitHubリポジトリにアクセスできる状態にする。逆に言えば、このstepがないと「Dockerfileが見つかりません」といったエラーに陥るはず。ドキュメントはこちら。Set up QEMU, Set up Docker Buildx
docker/setup-qemu-action@v1
docker/setup-buildx-action@v1
はいずれも必要な機能を利用可能にするためのactionという程度の認識でよいと思う。Login to GitHub Container Registry
docker/login-action@v1
というactionでログイン処理を行う。${{ secrets.CR_PAT }}
は先ほど作成したPersonal Access Tokenを参照している。Docker Hub やGitLabにも対応していて、ドキュメントにはそれぞれの対応方法が記載されている。Push to GitHub Container Registry
docker/build-push-action@v2
というactionでdockerイメージのbuildとpushを行う。tags:
でタグも指定できるが、この段階ではlatest
としておく。動作確認
ファイルの準備ができたら
git push
するだけで、YAMLで定義したワークフローが実行される。以下の画面のようにログも確認できる。問題なければGitHub右上の自分のアイコンから
Your profile
>Packages
でbuildされたdockerイメージを確認できる。デフォルトでprivateになるようなので、publicにしたければ変更してしまう。あとはdocker run
して問題なければOK3。docker run -it --rm ghcr.io/dr666m1/qiita_starwars:latestYAMLファイル作成②
次にタグを指定できるよう、YAMLファイルを以下の通り変更する。
name: Publish Docker image on: push jobs: main: name: Push Docker image to Docker Hub runs-on: ubuntu-latest steps: - name: Prepare # 追加 id: prep run: | if [[ $GITHUB_REF == refs/tags/* ]]; then TAG=${GITHUB_REF#refs/tags/} else TAG="latest" fi echo "::set-output name=tag::${TAG}" - name: Checkout uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} - name: Push to GitHub Container Registry uses: docker/build-push-action@v2 with: push: true tags: ghcr.io/dr666m1/qiita_starwars:${{ steps.prep.outputs.tag }} # 変更主な変更点はPrepareというstepの追加。
run:
でshell(デフォルトはbash4)で実行されるコマンドを指定する。ここでは$GITHUB_REF
環境変数5によって処理を変えていて、タグの名前を含めばそれを、なければlatest
をTAG
に代入している。echo "::set-output name=tag::${TAG}"
はワークフローコマンドと呼ばれるもので、ここではTAG
の値を後続のstepで参照できるようにしている。${{ steps.prep.outputs.tag }}
が実際に参照している部分。この変更によって、GitHubにpushしたタグに応じてdockerイメージのタグも変更されるようになる。例えば以下のように実行すれば、dockerイメージのタグも
1.0
になる。git tag 1.0 git push --tags
最後に
もしDocker HubからGitHub Container Registryに移行したくなっても、これで概ね困らなそう。GitHub Actionsは自動テストなど、もっといろいろなことに使えるはずなので、時間があるときに勉強したい。
Github Packagesでは、代わりにGITHUB_TOKENが使えたらしい ↩
Dockerfileを見ての通りだが、この例だとスターウォーズの上映が始まる(
telnet towel.blinkenlights.nl
)のでCtrl+]
>quit
で抜ける ↩
- 投稿日:2020-09-16T21:20:55+09:00
Django + Docker
はじめに
この記事ではDjango + Dockerのアプリ開発でおきたエラーとその対処法を書いていきます。
ERROR: No container found for web_1
いろいろ試してみてたのですが、一向に対処法がわからなかったのですが、次のようにターミナルに打ち込めば解決しました。
terminal$ docker-compose up -d参考記事
ERROR: No container found for web_1 #11045TypeError: Field 'id' expected a number but got datetime.datetime(2020, 9, 16, 2, 52, 51, 44897, tzinfo=).
models.pyのForignkeyがあるところに次のように追記しました。
models.pyuser = models.OneToOneField( User, verbose_name='ユーザー', on_delete=models.CASCADE, default=1 #追記 )これで解決しました。
django.db.utils.OperationalError: could not translate host name "db" to address: Name or service not known
sqlite3を使っていたのですが、このエラーが頻繁に出るので、Postgresqlを導入しました。
手順としてはこちらを参照してください。
ERROR: yaml.scanner.ScannerError: while scanning for the next token
このエラーでは「docker-compose.yml」のインデントを確認してみてください。
コメントアウトしているものでも、インデントがずれていると怒られるので注意してください。yaml.parser.ParserError: while parsing a block mapping
このエラーでも「docker-compose.yml」のインデントを確認してみてください。
- 投稿日:2020-09-16T21:03:16+09:00
[Docker] Hugo を利用するための環境構築
概要
本記事では、Hugo(静的サイトジェネレーター) を Docker で動かすための仮想環境を作る手順についてまとめる
環境
VSCodeのインストール
参考:VSCodeでDocker入門手順
利用可能な image を探す(仮想環境(コンテナ)つくる材料)
Docker で環境構築する際に、すでに利用することができる image がないか調べる
Hugo の公式サイト で、Docker と調べると、公式が推奨する image があったので、以下を利用する。
https://hub.docker.com/r/klakegg/hugo/
docker-compose.yml
を作成klakegg/hugo に記載されている以下のサンプルを元に
docker-compose.yml
を作成する
本記事では、仮想環境の中で「hugo」のコマンドをたたくことを目標とするので、以下のように記述した
docker-compose.ymlversion: '3' services: hugo: image: klakegg/hugo:0.74.3-ubuntu volumes: - ".:/src" entrypoint: bash ports: - "1313:1313" tty: true working_dir: /srcそれぞれのタグについて
docker-compose.ymlversion: '3' # 最新版は'3' services: # 固定 servicename: # 任意のサービスの名前をつける image: イメージ名: タグ名 # Docker Hub から利用する image を指定 volumes: - ローカルのフォルダのパス:コンテナのフォルダのパス #ローカルと仮想マシンのフォルダの紐付け entrypoint: 処理 # entrypoint: デフォルトの entrypoint の上書きしたいときに記載 ports: # 「hugo server」を実行したいため - "ホスト側:コンテナ側" tty: true # Attach Shell でコンテナに入る時は必須 working_dir: コンテナのフォルダパス #コンテナ内のワーキングディレクトリport について補足
「hugo server」 を使うことで、hugo で作成した画面を確認することができる
そこで、デフォルトでは port 1313 を利用するが、コンテナ側で起動した server をローカルから利用するために は、ローカルとコンテナのポートを繋げる必要がある
仮想環境の構築コマンドを実行
docker-compose up -d
コンテナの作成完了! [Attach Shell] をクリックし、作成したコンテナに入る
「hugo version」 と入力し、hugo のバージョンが返って来れば OK
image を
klakegg/hugo:0.74.3-ubuntu
にした理由当初は、[Default minimal image based upon Busybox:] にある [Hugo 0.74.3: 0.74.3] の利用を検討していたが、「bash」コマンドが使えなかった。そのため、このコマンドが利用できる [hugo:0.74.3-ubuntu]を採用した。以下に変更までの経緯を示す
Docker hub でタグの確認
image の中身について [Tags] で検索し、確認
Hugo 0.74.3 では、ENTRYPOINT で hugo が呼び出されている。
「hugo」コマンドの実行は起動時ではなく、任意のタイミングで行いたいdocker-compose.yml の修正
entrypoint: bash
と書くことで image の entrypoint を上書きし、起動時に何もしないようにする。docker-compose.ymlversion: '3' services: hugo: image: klakegg/hugo:0.74.3 volumes: - ".:/src" entrypoint: bash ports: - "1313:1313" tty: true working_dir: /src仮想環境の構築
仮想環境の構築コマンドを実行する
docker-compose up -dエラーが発生し、コンテナが作成できない。
デフォルトのBusyBox
タグ ではbash
コマンドが使えない参考
docker-compose.ymlの書き方について解説してみた
Docker Hub の概要
Compose ファイル リファレンス
- 投稿日:2020-09-16T20:45:53+09:00
【備忘録】Docker版 Db2環境 取得手順
1. はじめに
以前にLinux環境にDb2を導入する手順をまとめました。
【備忘録】Db2 インストール手順まとめ(Linux)
https://qiita.com/Haruka-Ogawa/items/9576399209b32f3016eaDb2は 2017年から Docker版が提供されおり、
Docker storeからpullすることで より手軽にDb2環境を使用することが可能です。今回は、DockerのDb2コンテナを取得する手順をまとめます。
2. 準備
PC に Docker を導入しておきます。
今回は Mac PC に Docker v19.03.12 を導入しています。$ docker -v Docker version 19.03.12, build 48a66213fe3. 作業
3-1. イメージ取得
まず、Db2イメージを取得します。
イメージの取得 には docker pullコマンドを使用します。
以下リンク先を開き、画面右側にある Db2イメージ取得のための docker pull コマンド をコピーします。https://hub.docker.com/r/ibmcom/db2
コピーした docker pull コマンドを実行します。
$ docker pull ibmcom/db2 Using default tag: latest latest: Pulling from ibmcom/db2 524b0c1e57f8: Pull complete e7a9171c839a: Pull complete f4447742b873: Pull complete db90696d3502: Pull complete 6acc1312ab24: Pull complete 67e9a72bc07a: Pull complete 2b9e6b7678c7: Pull complete Digest: sha256:cf95dd272a4f99d7f9119945ecad04b64ad3a2badc8a6682f1105aa87279da60 Status: Downloaded newer image for ibmcom/db2:latest docker.io/ibmcom/db2:latest[参考] Docker ドキュメント:pull
https://docs.docker.jp/engine/reference/commandline/pull.html3-2. イメージ確認
docker images コマンドで 取得したイメージ一覧を表示し、
db2イメージ が取得されたことを確認します。$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ibmcom/db2 latest d6b3abc02d57 2 months ago 2.69GB[参考] Docker ドキュメント: images
https://docs.docker.jp/engine/reference/commandline/images.html3-3. コンテナ作成・起動
docker runコマンドを実行し、Db2 コンテナ を作成・起動します。
今回実行したコマンドは、 Docker Hub:ibmcom/db2 のガイド を参考にしています。$ docker run -itd --name mydb --privileged=true -p 50000:50000 -e LICENSE=accept -e DB2INST1_PASSWORD=passw0rd -e DBNAME=testdb -v /Users/ogawa/db2fs:/database ibmcom/db2 67070db8cf20d82a9be8b45454eb1d5239c6c4d33b685c8ab9503a3bcc84e68b[参考] Docker Hub:ibmcom/db2
https://hub.docker.com/r/ibmcom/db2[参考] Docker ドキュメント: run
https://docs.docker.jp/engine/reference/commandline/run.html3-4. コンテナ ログ確認
docker logsコマンドで コンテナのログを確認し、
コンテナが作成・起動されたことを確認します。$ docker logs -f mydb (*) Previous setup has not been detected. Creating the users... (*) Creating users ... (*) Creating instance ... DBI1446I The db2icrt command is running. DB2 installation is being initialized. Total number of tasks to be performed: 4 Total estimated time for all tasks to be performed: 309 second(s) Task #1 start Description: Setting default global profile registry variables Estimated time 1 second(s) Task #1 end Task #2 start Description: Initializing instance list Estimated time 5 second(s) Task #2 end Task #3 start Description: Configuring DB2 instances Estimated time 300 second(s) Task #3 end Task #4 start Description: Updating global profile registry Estimated time 3 second(s) Task #4 end The execution completed successfully. For more information see the DB2 installation log at "/tmp/db2icrt.log.77". DBI1070I Program db2icrt completed successfully. 09/09/2020 03:16:06 0 0 SQL1032N No start database manager command was issued. SQL1032N No start database manager command was issued. SQLSTATE=57019 (*) Cataloging existing databases ls: cannot access /database/data/db2inst1/NODE0000: No such file or directory (*) Applying Db2 license ... LIC1402I License added successfully. LIC1426I This product is now licensed for use as outlined in your License Agreement. USE OF THE PRODUCT CONSTITUTES ACCEPTANCE OF THE TERMS OF THE IBM LICENSE AGREEMENT, LOCATED IN THE FOLLOWING DIRECTORY: "/opt/ibm/db2/V11.5/license/en_US.iso88591" (*) Saving the checksum of the current nodelock file ... (*) Updating DBM CFG parameters ... DB20000I The UPDATE DATABASE MANAGER CONFIGURATION command completed successfully. DB20000I The UPDATE DATABASE MANAGER CONFIGURATION command completed successfully. DB20000I The UPDATE DATABASE MANAGER CONFIGURATION command completed successfully. No Cgroup memory limit detected, instance memory will follow automatic tuning (*) Remounting /database with suid... (*) Nothing appears in the Db2 directory. will skip update/upgrade. (*) Code level is the same. No update/upgrade needed. DB2 State : Operable DB2 has not been started Starting DB2... 09/09/2020 03:16:35 0 0 SQL1063N DB2START processing was successful. SQL1063N DB2START processing was successful. (*) User chose to create testdb database (*) Creating database testdb ... DB20000I The CREATE DATABASE command completed successfully. DB20000I The ACTIVATE DATABASE command completed successfully. 09/09/2020 03:18:38 0 0 SQL1026N The database manager is already active. SQL1026N The database manager is already active. ### Enabling LOGARCHMETH1 Database Connection Information Database server = DB2/LINUXX8664 11.5.4.0 SQL authorization ID = DB2INST1 Local database alias = TESTDB DB20000I The UPDATE DATABASE CONFIGURATION command completed successfully. SQL1363W One or more of the parameters submitted for immediate modification were not changed dynamically. For these configuration parameters, the database must be shutdown and reactivated before the configuration parameter changes become effective. ### Restarting DB2 09/09/2020 03:18:46 0 0 SQL1064N DB2STOP processing was successful. SQL1064N DB2STOP processing was successful. 09/09/2020 03:18:51 0 0 SQL1063N DB2START processing was successful. SQL1063N DB2START processing was successful. ### Making backup directory and performing backup Backup successful. The timestamp for this backup image is : 20200909031855 (*) Applying autoconfiguration for instance ... Database Connection Information Database server = DB2/LINUXX8664 11.5.4.0 SQL authorization ID = DB2INST1 Local database alias = TESTDB DB20000I The UPDATE DATABASE CONFIGURATION command completed successfully. SQL1363W One or more of the parameters submitted for immediate modification were not changed dynamically. For these configuration parameters, the database must be shutdown and reactivated before the configuration parameter changes become effective. DB20000I The UPDATE DATABASE CONFIGURATION command completed successfully. DB20000I The UPDATE DATABASE CONFIGURATION command completed successfully. SQL1363W One or more of the parameters submitted for immediate modification were not changed dynamically. For these configuration parameters, the database must be shutdown and reactivated before the configuration parameter changes become effective. DB20000I The SQL command completed successfully. 09/09/2020 03:19:15 0 0 SQL1064N DB2STOP processing was successful. SQL1064N DB2STOP processing was successful. 09/09/2020 03:19:20 0 0 SQL1063N DB2START processing was successful. SQL1063N DB2START processing was successful. (*) Skipping TEXT_SEARCH setup for database testdb because TEXT_SEARCH is not configured for the instance ... ssh-keygen: generating new host keys: RSA1 RSA DSA ECDSA ED25519 (*) All databases are now active. (*) Setup has completed. FALSE 2020-09-09-03.19.20.117938+000 I223959E393 LEVEL: Warning PID : 14939 TID : 139881437169536 PROC : db2start INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 FUNCTION: DB2 UDB, base sys utilities, sqleReleaseStStLockFile, probe:16076 MESSAGE : Released lock on the file: DATA #1 : String, 50 bytes /database/config/db2inst1/sqllib/ctrl/db2strst.lck 2020-09-09-03.19.37.389298+000 I224353E420 LEVEL: Warning PID : 14947 TID : 140530994374400 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 15 EDUNAME: db2wlmtm 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12 2020-09-09-03.20.07.369457+000 I224774E420 LEVEL: Warning PID : 14947 TID : 140530994374400 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 15 EDUNAME: db2wlmtm 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12 2020-09-09-03.20.37.353793+000 I225195E420 LEVEL: Warning PID : 14947 TID : 140530994374400 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 15 EDUNAME: db2wlmtm 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12 2020-09-09-03.21.07.337071+000 I225616E420 LEVEL: Warning PID : 14947 TID : 140530994374400 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 15 EDUNAME: db2wlmtm 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12 2020-09-09-03.24.02.151703+000 I226037E420 LEVEL: Warning PID : 14947 TID : 140530994374400 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 15 EDUNAME: db2wlmtm 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12 2020-09-09-03.24.02.031095+000 I226458E419 LEVEL: Warning PID : 14947 TID : 140530998568704 PROC : db2sysc 0 INSTANCE: db2inst1 NODE : 000 HOSTNAME: 67070db8cf20 EDUID : 14 EDUNAME: db2wlmt 0 FUNCTION: DB2 UDB, base sys utilities, sqleTimedSleep, probe:1182 DATA #1 : unsigned integer, 8 bytes 1.59962E+12 DATA #2 : unsigned integer, 8 bytes 1.59962E+12[参考] Docker ドキュメント:logs
https://docs.docker.jp/engine/reference/commandline/logs.html3-5. コンテナ確認
docker psコマンドで コンテナの一覧を表示し、
Db2コンテナの状態を確認します。$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 67070db8cf20 ibmcom/db2 "/var/db2_setup/lib/…" About an hour ago Up About an hour 22/tcp, 55000/tcp, 60006-60007/tcp, 0.0.0.0:50000->50000/tcp mydb[参考] Docker ドキュメント: ps
https://docs.docker.jp/engine/reference/commandline/ps.html3-6. コンテナ内でコマンド実行
docker execコマンドは、コンテナ内で任意のコマンドを実行させることができます。
bash を起動し、db2inst1にスイッチすることで、db2環境に入ります。$ docker exec -ti mydb bash -c "su - db2inst1" Last login: Wed Sep 9 04:48:57 UTC 2020[参考] Docker ドキュメント: exec
https://docs.docker.jp/engine/reference/commandline/exec.html3-7. Db2環境 確認
Db2コマンドが実行できることを確認します。
- db2のバージョン確認
db2levelコマンドを実行し、Db2のバージョンを確認します。
[db2inst1@67070db8cf20 ~]$ db2level DB21085I This instance or install (instance name, where applicable: "db2inst1") uses "64" bits and DB2 code release "SQL11054" with level identifier "0605010F". Informational tokens are "DB2 v11.5.4.0", "s2006161200", "DYN2006161200AMD64", and Fix Pack "0". Product is installed at "/opt/ibm/db2/V11.5".
- データベース接続
docker runコマンド実行時点で、データベースtestdbが作成されています。
connectコマンドで、データベースtestdbに接続します。[db2inst1@67070db8cf20 ~]$ db2 connect to testdb Database Connection Information Database server = DB2/LINUXX8664 11.5.4.0 SQL authorization ID = DB2INST1 Local database alias = TESTDB
- テーブル作成
データベースtestdbに、テーブルTBL1を作成してみます。
[db2inst1@67070db8cf20 ~]$ db2 "CREATE TABLE TBL1(COL1 INTEGER, COL2 VARCHAR(50))" DB20000I The SQL command completed successfully.
- データベース切断
terminateコマンドで、データベースtestdbから切断します。
[db2inst1@67070db8cf20 ~]$ db2 terminate DB20000I The TERMINATE command completed successfully.Db2コマンドを実行し、操作ができることを確認しました。
コンテナから出る時はexitコマンドを使用します。
[db2inst1@67070db8cf20 ~]$ exit logout4. コンテナ 起動・停止
作成したコンテナの起動・停止には、
docker startコマンド、docker stopコマンドを使用します。4-1. 起動
docker startコマンドで、Db2コンテナ(mydb)を起動します。
$ docker start mydb mydb[参考] Docker ドキュメント: start
https://docs.docker.jp/engine/reference/commandline/start.html4-2. 停止
docker stopコマンドで、Db2コンテナ(mydb)を停止します。
$ docker stop mydb mydb[参考] Docker ドキュメント: stop
https://docs.docker.jp/engine/reference/commandline/stop.html5. おわりに
今回は、Dockerコンテナとして提供されているDb2をpullしてみました。
Dockerが導入されたPCさえあれば とても手軽にDb2環境を使用することができ、
作業自体も10分ちょっとくらいでできたので、ちょっとDb2の動作確認などしたい場合などに便利だと感じました。参考情報
Db2とDocker
https://www.ibm.com/blogs/solutions/jp-ja/db2-docker/Docker Hub:ibmcom/db2
https://hub.docker.com/r/ibmcom/db2
- 投稿日:2020-09-16T20:38:31+09:00
Dockerでタグのついていない不要なイメージの一括削除
# タグ付けされていないイメージの一括削除 docker rmi $(docker images -f dangling=true -q)Docker-docs-ja|images
https://docs.docker.jp/engine/reference/commandline/images.html
- 投稿日:2020-09-16T20:38:31+09:00
Dockerでタグなしの不要なイメージを一括削除
はじめに
dockerを使っているとimageが容量を圧迫していきます。
不要なimageを削除する為のコマンドを備忘録の為、メモしておきます。コマンド
# タグ付けされていないイメージの一括削除 docker rmi $(docker images -f dangling=true -q)参考
Docker-docs-ja|images
https://docs.docker.jp/engine/reference/commandline/images.html
- 投稿日:2020-09-16T20:38:31+09:00
Dockerでタグなしimageを一括削除する方法
はじめに
dockerを使っているとimageが容量を圧迫していくことがあります。
1つ1つ削除するのも手間なので、タグなしimageを一括で削除する為のコマンドをメモしておきます。
コマンドのオプションの意味についても纏めておきます。タグなしimageを一括削除コマンド
docker rmi $(docker images -f "dangling=true" -q)上記のコマンドを実行すれば、タグなしimageを一括削除できます。
コマンドの説明
filterオプションでdanglingをtrueにすることで、タグなしimageを取得
docker images -f "dangling=true"# 実行結果 REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> c29504d0f8fd 2 weeks ago 1.21GB <none> <none> e6325cdc18c4 2 weeks ago 1.18GB
quietオプションでIDのみを取得
docker images -f "dangling=true" -q# 実行結果 c29504d0f8fd e6325cdc18c4
取得したIDを使用してimageを削除
docker rmi $(docker images -f "dangling=true" -q)詳しくは公式ドキュメントをご参照ください。
公式ドキュメント
Docker docs|docker images
https://docs.docker.com/engine/reference/commandline/images/
Docker docs|docker rmi
https://docs.docker.com/engine/reference/commandline/rmi/
- 投稿日:2020-09-16T18:29:19+09:00
ERROR: create _mysql-data: "_mysql-data" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed.
はじめに
※MySQL、Dockerのタグを付けましたが今回の内容には直接は関係ないです。
エラー内容
Docker立ち上げようと
docker-compose up -d
したらERROR: create _mysql-data: "_mysql-data" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed.というエラーが出てしまいました。みなさんこんな初歩的なミスはしないためかググってもなかなか同じ内容のエラーで悩んでる方が出てきませんでした。
原因
git pull 〇〇
でプロジェクトのURLをプルしたディレクトリ名をカタカナにしておりました。なので"[a-zA-Z0-9][a-zA-Z0-9_.-]"
という風にアルファベットか数字にしてねと怒られていたのでした。。
- 投稿日:2020-09-16T18:29:03+09:00
Docker for WindowsをアップデートしたらWSL2のdockerがエラーを吐いた件の対応
$ docker-compose ps ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running? If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.あれ、なにかしたっけ・・・。
そういえばDocker for Windowsがなにかアップデートしたような・・・。
名称 バージョン docker for desktop 2.3.0.5 Engine 19.03.12 Notary 0.6.1 Compose 1.27.2 Credential Helper 0.6.3 Kubernetes v1.16.5 とりあえずエラーをぐぐる
この設定を行ったところ、無事にWSL2内で動作することを確認した
$ docker-compose ps Name Command State Ports ------------------------------完了
何もなくてよかった。
- 投稿日:2020-09-16T17:21:17+09:00
dockerで手元のイメージを誰かに渡す方法
- 投稿日:2020-09-16T16:51:51+09:00
Docker+Sinatraで簡単なチャットアプリをつくる練習
Rubyの使い方をよく忘れるので、リハビリ用にRubyで簡単なWebアプリを作りました。また忘れた時のために、作る方法を書き残しておきます。
つくるのはNopochatというクソチャットアプリです。
投稿に「~も」というかわいらしい語尾が付くことで、言いづらい内容も心理的安全性を保ったまま送ることができる画期的なチャットですも。なお本稿で紹介する内容はあくまでプログラムを書く練習のためのものであり、本番環境で運用することは想定していません。
環境
Dockerを利用します。Rubyのインストールは必要ありません。
- Docker version 19.03.12
- docker-compose version 1.26.2
Sinatraの立ち上げ
まず適当なディレクトリを切って、開発を始めます。
$ mkdir sinatra-chat && cd $_プロジェクトをGitで管理する場合は、GitHubのgitignoreを取ってきてセットするのが良いと思います。
$ git init $ curl https://raw.githubusercontent.com/github/gitignore/master/Ruby.gitignore -o .gitignorehttps://hub.docker.com/_/ruby から使いたいバージョンのRubyイメージを取ってきてください。今回は
2.7-slim
を使います。まず
Gemfile
を初期化します。$ docker run --rm --volume $(pwd):/app --workdir /app ruby:2.7-slim bundle init $ docker run --rm --volume $(pwd):/app --workdir /app ruby:2.7-slim bundle add sinatra
Gemfile
とGemfile.lock
が生成されたのを確認したら、Dockerfile
を記述していきます。DockerfileFROM ruby:2.7-slim WORKDIR /app COPY Gemfile ./ COPY Gemfile.lock ./ RUN bundle config --local set path 'vendor/bundle' RUN bundle install CMD bundle exec ruby index.rbdocker-compose.ymlversion: '3' services: app: build: . volumes: - .:/app - /app/vendor/bundle ports: - 127.0.0.1:4567:4567アプリケーションの本体となる
index.rb
を作成します。index.rbrequire 'sinatra' configure do set :bind, '0.0.0.0' end get '/' do 'Hello Sinatra!' endhttp://localhost:4567/ にアクセスし、
Hello Sinatra!
と表示されたら成功ですブラウザリロードによる再読み込みの有効化
そのままでは、ファイルを編集してもSinatraサーバを再起動しなければ反映されません。
開発を始める前に、リロードでの再読み込みを有効にすると便利です。$ docker-compose run --rm app bundle add sinatra-contribindex.rbrequire 'sinatra' +require 'sinatra/reloader' if settings.development?
チャット機能の開発
チャット内容は後で永続化するので、とりあえず今は
@@chats
というクラス変数に格納していきます。index.rbget '/' do @@chats ||= [] erb :index, locals: { chats: @@chats.map{ |chat| add_suffix(chat) }.reverse } end post '/' do @@chats ||= [] @@chats.push({ content: params['content'], time: Time.now } ) redirect back end def add_suffix(chat) { **chat, content: "#{chat[:content]}も" } endHTMLテンプレートにはerbを使います。
views/
というディレクトリを切って、そこにindex.erb
を格納すると、erb :index
で呼び出すことができます。views/index.erb<form action="/" method="post"> <input name="content" placeholder="投稿" /> <button type="submit">送信</button> </form> <table> <% chats.each do |chat| %> <tr> <td><%= chat[:content] %></td> <td><%= chat[:time] %></td> </tr> <% end %> </table>これで最低限、チャットができるようになります。
データベースへの保存
チャット内容をMySQLに保存します。mysql2 Gemをインストールします。
$ docker-compose run --rm app bundle add mysql2https://hub.docker.com/_/mysql からMySQLの好きなバージョンを取ってきて使います。またappの方にも接続情報を環境変数としてセットします。
docker-compose.ymlversion: '3' services: app: build: . volumes: - .:/app - /app/vendor/bundle ports: - 127.0.0.1:4567:4567 + environment: + - MYSQL_HOST=db + - MYSQL_USER=root + - MYSQL_PASS=secret + - MYSQL_DATABASE=nopochat_development + db: + image: mysql:5.7 + volumes: + - .:/app + - /var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=secret
index.rbrequire 'sinatra' require 'sinatra/reloader' if settings.development? +require 'mysql2' (以下略)mysql2 Gemの利用に必要なパッケージをインストールします。
DockerfileFROM ruby:2.7-slim WORKDIR /app +RUN apt-get update && apt-get install -y \ + build-essential \ + libmariadb-dev \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* (以下略)セットした環境変数に基づいてデータベースクライアントを取得するメソッドを定義します。
index.rbdef db_client() Mysql2::Client.default_query_options.merge!(:symbolize_keys => true) Mysql2::Client.new( :host => ENV['MYSQL_HOST'], :username => ENV['MYSQL_USER'], :password => ENV['MYSQL_PASS'], :database => ENV['MYSQL_DATABASE'] ) end今回は
GET /initialize
にアクセスしたらデータベースを初期化する仕様とします(実際の運用ではこのような仕様はあり得ませんが...)index.rbget '/initialize' do client = Mysql2::Client.new( :host => ENV['MYSQL_HOST'], :username => ENV['MYSQL_USER'], :password => ENV['MYSQL_PASS'] ) client.query("DROP DATABASE IF EXISTS #{ENV['MYSQL_DATABASE']}") client.query("CREATE DATABASE IF NOT EXISTS #{ENV['MYSQL_DATABASE']} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci") client = db_client client.query(<<-EOS CREATE TABLE IF NOT EXISTS chats ( id INT AUTO_INCREMENT, name TEXT, content TEXT, time DATETIME, PRIMARY KEY(id) ) EOS ) redirect '/' endchatsというテーブルからデータを出し入れするメソッドを定義します。
index.rbdef chat_push(content, name="名無し") db_client.prepare( "INSERT into chats (name, content, time) VALUES (?, ?, NOW())" ).execute(name, content) end def chats_fetch() db_client.query("SELECT * FROM chats ORDER BY time DESC") end定義したメソッドを使って、
GET /
とPOST /
を書き換えます。index.rbget '/' do - @@chats ||= [] + chats = chats_fetch erb :index, locals: { - chats: @@chats.map{ |chat| add_suffix(chat) }.reverse + chats: chats.map{ |chat| add_suffix(chat) } } end post '/' do - @@chats ||= [] - @@chats.push({ content: params['content'], time: Time.now } ) + chat_push(params['content']) redirect back endアプリを起動して http://localhost:4567/initialize にアクセスすると、立ち上がります。
これでアプリを再起動しても、いちどチャットした内容が消えることはありません。ログイン機能
セッションストレージにはDB(MySQL)を利用します。
ユーザ名とパスワードを持つusers
テーブルと、セッションを保存するsessions
テーブルを定義します。なお本来passwordは暗号化してハッシュを持つようにします。また、sessionsの定期的な削除処理も必要です。index.rbclient.query(<<-EOS CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT, name VARCHAR(255) UNIQUE, password TEXT, PRIMARY KEY(id), INDEX key_index (name) ); EOS ) client.query(<<-EOS CREATE TABLE IF NOT EXISTS sessions ( id INT AUTO_INCREMENT, session_id VARCHAR(255) UNIQUE, value_json JSON, PRIMARY KEY(id), INDEX key_index (session_id) ); EOS ) user_push('admin', 'admin')ユーザの追加・認証処理を定義します。
index.rbdef user_push(name, pass) db_client.prepare( "INSERT into users (name, password) VALUES (?, ?)" ).execute(name, pass) end def user_fetch(name, pass) result = db_client.prepare("SELECT * FROM users WHERE name = ?").execute(name).first return unless result result[:password] == pass ? result : nil endセッションの追加・取得処理を定義します。
index.rbdef session_save(session_id, obj) db_client.prepare( "INSERT into sessions (session_id, value_json) VALUES (?, ?)" ).execute(session_id, JSON.dump(obj)) end def session_fetch(session_id) return if session_id == "" result = db_client.prepare("SELECT * FROM sessions WHERE session_id = ?").execute(session_id).first return unless result JSON.parse(result&.[](:value_json)) endcookieを使うため
require 'sinatra/cookies'
を追加します。index.rbrequire 'sinatra' require 'sinatra/reloader' if settings.development? +require 'sinatra/cookies' require 'mysql2'
POST /login
とGET /logout
を定義します。index.rbpost '/login' do if user = user_fetch(params['name'], params['pass']) cookies[:session_id] = SecureRandom.uuid if cookies[:session_id].nil? || cookies[:session_id] == "" session_save(cookies[:session_id], { name: user[:name] }) end redirect back end get '/logout' do cookies[:session_id] = nil redirect back end
GET /
とPOST /
を修正します。index.rbget '/' do + name = session_fetch(cookies[:session_id])&.[]("name") chats = chats_fetch erb :index, locals: { + name: name, chats: chats.map{ |chat| add_suffix(chat) } } end post '/' do - chat_push(params['content']) + name = session_fetch(cookies[:session_id])&.[]("name") + chat_push(params['content'], name) redirect back endViewのフォーム部分を書き換え、ログインしていない時はログインフォームが、ログイン後には投稿フォームが表示されるようにします。
vieqs/index.erb<% if name %> <p>こんにちは<%= name %>さん</p> <a href="/logout">ログアウト</a> <form action="/" method="post"> <input name="content" placeholder="投稿" /> <button type="submit">送信</button> </form> <% else %> <form action="login" method="post"> <input name="name" placeholder="ユーザ名"> <input name="pass" placeholder="パスワード"> <button type="submit">ログイン</button> </form> <% end %>http://localhost:4567/initialize にアクセスし、
admin
ユーザでログインできたら成功です。Appの複数台化
docker-compose.yml
を下記のように修正します。
appを2つにして、あらたにWebサーバとなるNginxのコンテナを追加します。
Sinatraの4567ポートを閉じて、Nignx用の8080ポートを開けます。Nginxは https://hub.docker.com/_/nginx から好きなバージョンを取ってきて使います。
docker-compose.ymlversion: '3' services: - app: + app1: &app build: . volumes: - .:/app - /app/vendor/bundle - ports: - - 127.0.0.1:4567:4567 environment: - MYSQL_HOST=db - MYSQL_USER=root - MYSQL_PASS=secret - MYSQL_DATABASE=nopochat_development + app2: + <<: *app + web: + image: nginx:1.19-alpine + volumes: + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf + ports: + - 127.0.0.1:8080:80 (以下略)Nginxの設定ファイルを配置します。
app1
とapp2
を振り分けるようにします。nginx/default.confupstream apps { server app1:4567; server app2:4567; } server { listen 80; proxy_set_header Host $host:8080; location / { proxy_pass http://apps; } }http://localhost:8080/ にアクセスします。もしログイン処理がうまくできていないと、アクセスするたびにセッションが切り替わってログアウトしたりします。
RubyからRustを呼び出す
序盤に挙げた、語尾に「も」を付与する処理
def add_suffix(chat) { **chat, content: "#{chat[:content]}も" } endこれをRustで書いてRubyから呼び出してみます。
https://hub.docker.com/_/rust から好きなバージョンを取ってきます。今回は
rust:1.46-slim
を使います。
下記コマンドで、rust_lib
というディレクトリにRustのプロジェクトを作成します。$ docker run \ --rm \ --volume $(pwd):/app \ --workdir /app \ --env USER=root \ rust:1.46-slim cargo new rust_lib --lib$ cd rust_libお好みでGitHubの.gitignoreから取ってきてセットします。
$ curl https://raw.githubusercontent.com/github/gitignore/master/Rust.gitignore -o .gitignoreCargoでlibc crateを追加、crate-typeを
"dylib"
に指定します。rust_lib/Cargo.toml[dependencies] libc = "0.2.77" [lib] name = "rust_lib" crate-type = ["dylib"]Rustで処理を書いていきます。
rust_lib/src/lib.rsextern crate libc; use libc::*; use std::ffi::{CStr, CString}; #[no_mangle] pub extern fn add_suffix(s: *const c_char) -> CString { let not_c_s = unsafe { CStr::from_ptr(s) }.to_str().unwrap(); let not_c_message = format!("{}も", not_c_s); CString::new(not_c_message).unwrap() }ビルドします。
$ docker run \ --rm \ --volume $(pwd):/app \ --workdir /app \ rust:1.46-slim cargo build
rust_lib/target/release/librust_lib.so
がビルドされていれば成功です。$ nm target/release/librust_lib.so | grep add_suffix 00000000000502c0 T add_suffixRuby FFI Gemを使って、RubyからRustを呼び出す処理を書いていきます。
$ docker-compose run --rm app1 bundle add ffiindex.rbrequire 'sinatra' require 'sinatra/reloader' if settings.development? require 'sinatra/cookies' require 'mysql2' +require 'ffi'
extend FFI::Library
して、先程のrust_lib/target/release/librust_lib.so
を読み込んで使います。FFIのwikiを参考に、引数と返り値の型を指定します。index.rb# Rustから呼び出すモジュールの設定 module RustLib extend FFI::Library ffi_lib('rust_lib/target/release/librust_lib.so') attach_function(:add_suffix, [:string], :string) end
GET /
を修正します。index.rbget '/' do name = session_fetch(cookies[:session_id])&.[]("name") chats = chats_fetch erb :index, locals: { name: name, - chats: chats.map{ |chat| add_suffix(chat) } + chats: chats.map{ |chat| { **chat, content: RustLib::add_suffix(chat[:content]).force_encoding("UTF-8") } } } end以上です。完成品は下記になります。
https://github.com/s2terminal/sinatra-chat
参考
- 投稿日:2020-09-16T14:25:10+09:00
雰囲気でコンテナを立ち上げないために。あらためて学ぶDocker Composeの基礎
はじめに
この記事は、
Docker-compose.yml
を書いたり、docker-compose
コマンドを使ってアプリケーションを開発したり運用したことがあるが、——全然わからない、俺は雰囲気で複数コンテナを立ち上げているーー
という方(主に自分)に向けて、あらためてDocker Composeがどういうものかを、簡単に説明した記事です。
この記事のゴール?
- なぜ複数コンテナの管理ツールが必要になるのかを把握する
- 複数コンテナ実行管理ツールであるDocker Composeの基礎を理解する
複数コンテナ管理の基礎を学ぶ?
1. なぜ複数コンテナの管理ツールが必要になるのか
1.1. 複数コンテナを運用するパターン
現在の一般的な構成である三層アーキテクチャのWebアプリケーションをDockerを使って開発・運用することを例として挙げます。
プロセスとしては、Web・アプリケーション・データベースの3つのプロセスが考えられます。これを1コンテナで実現するのは、(できるにはできるみたいですが)あまり良い構成とは言えません。
スケール・管理がしにくく、プロセスが一つでも落ちるとコンテナが落ちてしまうなど、リスクが高いためです。なので、現在は1コンテナ=1プロセスとして、それぞれの役割ごとにコンテナを立てるのが一般的になっています。必要に応じてコンテナを追加したり差し替えができるため、スケールや変更が容易になります。
1.2. 管理ツールを使わずに複数コンテナを動かすと...?
ここで、コンテナの起動・管理方法について考えます。1コンテナ=1プロセスなのですから、例えば今回の環境を立ち上げる際には、計3回
docker build
&docker run
をすることになります。これは、環境の構成コンテナが増えるごとにコマンドを打つ回数が増えていくことを意味します。また、ポートマッピングの設定など、それぞれのコンテナを起動する際にオプションでいちいち指定しなければなりません。シェルスクリプト化するにしても、コンテナの立ち上げ順序等もあるため、環境の管理は面倒でしょう。例えばのイメージ$ docker run --name mysql #この後にvolumesなどのいろいろなオプションがつく $ docker run --name nginx $ docker run --name rails $ #...コンテナの数だけ回数は増えるこうなると、環境を構築するのが面倒になりますし、手動でそれぞれのコンテナを運用することになります。単純に管理・維持が大変になり、"環境構築の手軽さ"というDockerの特徴を潰すことになります。
2. Docker Compose とは?
ここで、Docker Composeの登場です。
Docker Compose とは、複数コンテナで構成されるプロジェクトの起動・停止などの手順を、yamlファイルに定義した設定内容に基づいて自動的にしてくれるツールです。docker-compose.yml(適当に作った例)version: '3' services: db: image: postgres:alpine volumes: - ./tmp/db:/var/lib/postgresql/data networks: - sampleapp web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - ./web/app/ ports: - '8080:8080' depends_on: - db networks: - sampleapp networks: sampleapp: external: true各プロセスのDockerfileを用意した上で、上記のように
docker-compose.yml
にプロジェクトの設定内容を記述しておき、$ docker-compose upとすると、簡単に環境を立ち上げることができます。
2.1. docker-compose.yml で定義する内容
さて、
docker-compose.yml
では、どのようなことが設定できるのでしょうか?
Compose ファイル・リファレンスによると、Compose ファイルは YAML ファイルであり、 サービス(services) 、 ネットワーク(networks) 、 ボリューム(volumes) を定義します。
とあります。
うーん、なんとなく今まで雰囲気でdocker-compose.yml
に書いてきたから、よくわかっていない...(心の声)
ということで、それぞれについてあらためて確認していきたいと思います。2.1.1. services
servicesには、プロジェクトを構成する各コンテナの情報を定義します。ここには、各コンテナの
docker run
時に指定していたオプションを記述することができます。ポートマッピングの設定や、後述するvolumesやnetworksの設定などもここに記述することで、docker-compose up
でのコンテナ一括起動時に反映してくれるようになります。2.1.2. volumes
続いて、
volumes
に記述する内容です。
起動したコンテナで扱うデータは、コンテナが削除されると一緒に消えてしまいます。また、コンテナを複数起動した際、そのままではお互いのファイルシステムを直接参照できません。ですが、コンテナにはボリューム(volume)と呼ばれる、ディレクトリやファイルをマウントできる領域があり(実体はホスト上に自動生成されるディレクトリ
/var/lib/docker/volumes
)、異なるコンテナでも、docker
コマンドのオプションで同じvolumeを指定することで、データの共有が可能になります。Docker Compose では、その設定も各コンテナ起動時にいちいちオプションをつける代わりに、
docker-compose.yml
のvolumes
に定義することで、docker-compose up
でのコンテナ一括起動時に反映してくれるようになります。2.1.3. networks
最後に
networks
に定義する内容についてです。
今回の例では、アプリケーションを構成するWeb・アプリケーション・DBの各コンテナを通信させる必要がありました。
ここで、Dockerには、3つの標準ネットワークモデルがあり、設定によってホスト側のネットワークに直接接続したり、コンテナ間を通信させることができます(わかりやすい参考記事)。特に何も設定せずにコンテナを複数起動させている場合、各コンテナはIPアドレスを指定して通信することは可能ですが、コンテナ名を指定して通信することはできません。コンテナ名で通信させるにはユーザー独自の
Dockerネットワーク
を設定する必要があります。その設定も、本来なら
docker network
コマンドでいちいち指定する必要がありますが、Docker Composeではdocker-compose.yml
のnetworks
に定義することで、docker-compose up
でのコンテナ一括起動時に反映してくれるようになります。まとめ
管理ツールを使わずに、複数コンテナ構成プロジェクトを運用しようとすると、各コンテナ実行時にいちいちコマンドを走らせる&オプションで設定する必要があるため、環境構築や環境の維持・再現が大変
Docker Composeを使うと、
docker-compose.yml
に各コンテナの情報をまとめて定義しておくことができ、1コマンドで環境が構築できるDocker Composeによる管理は、特に
network
やvolume
が複雑な場合に真価を発揮する引用・参考記事
- 投稿日:2020-09-16T11:30:02+09:00
チームで共有するための『Rails 6 x MySQL 8』Docker環境構築手順
今回はRails 6とMySQL 8を組み合わせたWebアプリケーションのDocker環境を構築する手順について紹介します。
Rails 6からwebpackerが標準でインストールされるようになったり、MySQL 8からユーザー認証の方式が変わったりと環境構築でつまる部分がいろいろとあったため参考になればと思います。
複数人でもスムーズに開発ができるようにするためリモートリポジトリからcloneしてきたらdocker-compose upするだけでアプリケーションが立ち上がるという環境をゴールにします。
各種バージョンは以下の通りです。
- Ruby on Rails: 6.0.3.2
- Ruby: 2.7.1
- MySQL: 8.0.21
実行環境はDocker Desktop for Mac(バージョン 2.3.0.4)を利用しています。
Railsアプリケーションの準備
ディレクトリの作成・移動をします。
今回作成するRailsアプリケーション名はsample_app
とします。$ mkdir sample_app && cd $_rubyイメージを利用してローカル環境にGemfileを作成します。
-v
はバインドマウント(ホストとコンテナのディレクトリの同期)のオプションです。ホストのカレントディレクトリとコンテナのワークディレクトリを同期させることで、コンテナ上で作成されるファイルをホストに配置します。
$ docker run --rm -v `pwd`:/sample_app -w /sample_app ruby:2.7.1 bundle init作成されたGemfileの
gem "rails"
の部分をアンコメントし、railsのバージョンを指定します。Gemfile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - # gem "rails" + gem "rails", '~> 6.0.3.2'
rails new
を実行するDocker環境を構築するためDockerfileを作成します。Rails 6ではアプリケーションを作成する際に
rails webpacker:install
も実行されるのでyarnのインストールを忘れずにしましょう。
今回はnpm
を利用してyarn
をインストールします。DockerfileFROM ruby:2.7.1 RUN apt-get update -qq && \ apt-get install -y nodejs \ npm && \ npm install -g yarn # 作業ディレクトリを/sample_appに指定 WORKDIR /sample_app # ローカルのGemfileをDokcerにコピー COPY Gemfile /sample_app/Gemfile # /sample_appディレクトリ上でbundle install RUN bundle installDockerfileをビルドして作成されたイメージを利用してコンテナを起動し、コンテナ上で
rails new
をします。$ docker build -t sample_app . $ docker run --rm -v `pwd`:/sample_app sample_app rails new . –skip-bundle --database=mysql
docker-compose.yml
を作成します。今回は説明を簡略化するため、rootユーザーでMySQLに接続しています。
一般ユーザーで接続をする場合はMySQLのイメージに対して以下の環境変数を設定する必要があります。
環境変数 内容 MYSQL_USER ユーザー名 MYSQL_PASSWORD ユーザーパスワード データベースの情報は
mysql_data
という名前付きボリュームを作成して永続化します。docker-compose.ymlversion: '3' services: web: # Ruby on Railsが起動するコンテナ build: . ports: - '3000:3000' # localhostの3000ポートでアクセスできるようにする volumes: - .:/sample_app # アプリケーションファイルの同期 depends_on: - db command: ["rails", "server", "-b", "0.0.0.0"] db: # MySQLが起動するコンテナ image: mysql:8.0.21 volumes: - mysql_data:/var/lib/mysql # データの永続化 command: --default-authentication-plugin=mysql_native_password # 認証方式を8系以前のものにする。 environment: MYSQL_ROOT_PASSWORD: 'pass' MYSQL_DATABASE: 'sample_app_development' volumes: mysql_data: # データボリュームの登録上記の
docker-compose.yml
の補足説明をします。MySQLのDockerイメージでは
MYSQL_DATABASE
に設定された名前のデータベースを作成してくれます。
Ruby on Railsのdevelopment環境では[アプリケーション名]_development
というデータベースを利用するため、sample_app_development
をMYSQL_DATABASE
に登録しています。
これでrails db:create
を実行しなくてもdevelopment環境のデータベースを用意できます。MySQL 8からは認証方式が
mysql_native_password
からcaching_sha2_password
に変更されました。
MySQL 8標準のcaching_sha2_password
の認証方式だとデータベースへ接続できず、Railsアプリケーション起動時に以下のようなエラーメッセージが表示されてしまいます。Mysql2::Error::ConnectionError Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directoryそこで、
--default-authentication-plugin=mysql_native_password
で以前のmysql_native_password
の認証方式を利用するようにしています。次にRuby on Railsのデータベース接続設定を行います。
config/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: pass # (今回はrootなので)MYSQL_ROOT_PASSWORDと一致させる host: db # データベースのコンテナ名を設定するRailsアプリケーションの起動確認
Ruby on Rails 6とMySQL 8を組み合わせたDocker環境ができあがったので起動をしてみます。
$ docker-compose up
localhost:3000
にアクセスして以下の画面が表示されればOKです。データベースのデータの永続化についても確認をしてみます。
例としてscaffold
でevent
に関する機能を作成します。$ docker-compose exec web rails g scaffold event title:string $ docker-compose exec web rails db:migrate
localhost:3000/events/new
にアクセスし、例として『サンプルイベント』というレコードを登録してみます。コンテナを削除・起動してもデータが残っていればOKです。
$ docker-compose down $ docker-compose up $ docker-compose exec web rails c > Event.last.title => "サンプルイベント"テスト環境用のデータベースの作成
MYSQL_DATABASE
を利用してdevelopment環境のデータベースを作成することでdb:create
を実行することなくRailsアプリケーションを起動できるようにしました。しかし、テストコードで利用するtest環境のデータベース(
[アプリケーション名]_test
)が作られていないためこれだけでは開発環境としては不十分です。MySQLのDockerイメージでは
/docker-entrypoint-initdb.d
にスクリプト(.sql
、.sh
、.sql.gz
)を配置しておくとコンテナ起動時に実行してくれるという機能があります。1
この機能を活用してtest環境用のデータベースを作成します。スクリプトはアルファベット順で実行されるため、スクリプト間に依存関係がある場合はファイル名も意識してつけるようにしておきましょう。
$ mkdir docker-entrypoint-initdb.d && cd $_ $ vim 00_create.sql00_create.sql-- test環境用のデータベースを作成する CREATE DATABASE sample_app_test;なお、一般ユーザーのデータベースアクセス権は
MYSQL_DATABASE
に設定したデータベースのみとなっています。
ですので、一般ユーザーでデータベースに接続する場合はデータベースの作成だけでなく、以下のようなアクセス権の付与も実行する必要があります。01_grant.sql-- webappという名前の一般ユーザーを利用する場合 GRANT ALL ON `sample_app_test`.* TO webapp@'%';作成したスクリプトをコンテナ上で読み取れるようにするためバインドマウントを追加します。
docker-compose.ymlversion: '3' services: web: build: . ports: - '3000:3000' volumes: - .:/sample_app depends_on: - db command: ["rails", "server", "-b", "0.0.0.0"] db: image: mysql:8.0.21 volumes: - mysql_data:/var/lib/mysql + - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: 'pass' MYSQL_DATABASE: 'sample_app_development' volumes: mysql_data:データベースが自動作成されることを確認
dbコンテナを削除・起動し、自動でデータベースが作られるか確認をしてみます。
[アプリケーション名]_development
と[アプリケーション名]_test
のデータベースが存在していればOKです。# データベースの永続化情報も削除して0からデータベースを作成する $ docker-compose down --volumes $ docker-compose up $ docker-compose exec db mysql -uroot -ppass -D sample_app_development mysql> show databases; +------------------------+ | Database | +------------------------+ | information_schema | | mysql | | performance_schema | | sample_app_development | | sample_app_test | ← test用のdbが作成されている | sys | +------------------------+ 6 rows in set (0.00 sec)Railsアプリケーションからも正常に接続できます。
$ docker-compose exec web rails c > ENV['RAILS_ENV'] => "development $ docker-compose exec web rails c -e test > ENV['RAILS_ENV'] => "test"『clone → docker-compose up』だけで環境が立ち上がるようにする
DockerでRailsの開発環境を構築する方法としてよく見かけるのが以下のようなパターンです。
# コンテナを立ち上げる $ docker-compose up # データベースの作成 $ docker-compose exec web rails db:create # テーブルのマイグレーション $ docker-compose exec web rails db:migrateRailsアプリケーションとデータベースをdocker-composeで連携させ、アプリケーションで利用するデータベースはコンテナ上で構築するという方法です。
上記の方法でも問題はないのですが、この場合だと初回起動時にデータベースとテーブルの作成をコンテナ上で手動実行する手間がかかります。
複数人でDocker環境を共有する時のことを考えると、リモートリポジトリからアプリケーションファイルをcloneしてきたら
docker-compose up
をするだけで環境が立ち上がるのが理想です。共有メンバーに対して「初回起動時はデータベースの作成をコンテナ上で実施してね」とわざわざ伝えないといけない状況はできれば避けたいです。
ここからはリモートリポジトリからcloneしたら
docker-compose up
するだけでRailsアプリケーションが起動できるようにするための設定を行います。yarn installをコンテナ起動時に実行する
開発環境ではバインドマウト(ホストとコンテナのディレクトリの同期)を利用したソースコードの同期がよく利用されます。
リモートリポジトリからcloneしてきたアプリケーションファイルは
package.json
はありますが、node_modules
ディレクトリはありません。
そのため、cloneしたあとdocker-compose up
をするとnode_modules
がない状態のディレクトリがバインドマウントされます。その結果yarn install
の実行を促すエラーが発生し、アプリケーションが起動できません。======================================== Your Yarn packages are out of date! Please run `yarn install --check-files` to update. ======================================== To disable this check, please change `check_yarn_integrity` to `false` in your webpacker config file (config/webpacker.yml). yarn check v1.22.5 info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.これを防ぐにはコンテナ起動時に
yarn install
を実行する必要があります。
たとえば以下のようにすることでコンテナ起動時にyarn install
を実行できます。docker-compose.ymlversion: '3' services: web: build: . + command: ["./start.sh"] - command: ["rails", "server", "-b", "0.0.0.0"] ports: - '3000:3000' volumes: - .:/sample_app depends_on: - db db: image: mysql:8.0.21 command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: 'pass' MYSQL_DATABASE: 'sample_app_development'start.sh#!/bin/bash -eu yarn rails server -b '0.0.0.0'シェルのパーミッションを変更します。
$ chmod 755 start.shコンテナを起動する際のコマンドでシェルを呼び出し、シェルの中で
yarn install
を実行するようにしています。
yarn install
実行後、rails server
でRailsアプリケーションが起動するため先ほどのエラーが解消されます。マイグレーションを自動実行できるようにする
テーブルのマイグレーションも
yarn install
と同様、コンテナ起動時に呼び出されるシェルスクリプトで実行するようにします。start.sh#!/bin/bash -eu yarn + rails db:migrate rails server -b '0.0.0.0'しかし、
docker-compose.yml
のdepends_on
を利用することでコンテナの起動順は制御できますが、コンテナの起動を待つということはできないため2、dbコンテナの起動準備が終わる前にdb:migrate
が実行されるとマイグレーションが正常に行われません。マイグレーションの自動化をするにはdbコンテナの起動を待ってから
db:migrate
が実行されるようにする必要があります。データベースの準備を待つ方法にはいくつかありますが、今回はwait-for-itを利用する方法を紹介します。
wait-for-it.sh
をカレントディレクトリに配置し、docker-compose.yml
を以下のようにするとデータベースの起動を待ってからスクリプトが実行されます。docker-compose.ymlversion: '3' services: web: build: . - command: [""./start.sh"] + command: ["./wait-for-it.sh", "db:3306", "--", "./start.sh"] ports: - '3000:3000' volumes: - .:/sample_app depends_on: - db db: image: mysql:8.0.21 command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: 'pass' MYSQL_DATABASE: 'sample_app_development'まとめ
以上でRails 6 + MySQL 8のDocker環境の構築手順の紹介を終わります。
コンテナ起動時にシェルを実行することで、複数人でDocker環境を利用する場合でもスムーズに開発環境を構築できるようにしました。
なお、今回はコンテナ起動時にシェルを呼び出すことでyarn install
やdb:migration
を確実に実行するようにしましたが、コンテナ起動時のコマンドの制御はEntrykitと呼ばれるツールでも行えます。EntrykitについてはRailsのDocker環境にEntrykitを導入し、bundle installを自動実行させる方法で紹介していますので、興味のある方はご覧になってください。
- 今回のまとめ
- Rails 6からはyarnのインストールも事前に行う必要がある
- MySQL 8の認証エラーが発生した場合は標準の認証に戻すことで解決する
- コンテナ起動時にシェルを実行することでテーブル作成等の自動化が可能になる
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!
参考記事
- 投稿日:2020-09-16T10:48:53+09:00
AthrillのDockerコンテナ最小化手順
はじめに
以前書いたメモが出てきたので、記事にしときます。
AthrillをDockerで動かす方法は
https://qiita.com/kanetugu2018/items/f1368a6da7bdc773cfd9
で紹介されていますが、折角なのでできるだけ小さくしてみたいと思います。
箱庭で数匹・数十匹のAthrillを同時に動かしたりできると面白そうですよね。今回は、Dockerのscratchから構成したいと思います。
Athrillのstaticビルド
athrillを普通にビルドするとダイナミックリンクライブラリを利用するので、
何も入っていない環境で実行しようとするとコケます。このため、スタティックにビルドしなおします。
Makefileをこんな感じに変えて、
/trunk/src/build/target/linux_v850e2m/Makefile28: $(GCC) -O3 $(LFLAGS) $(AROBJS) -o $(TARGET) $(LIBS) -static再ビルドします。
$ make clean; makeDockerfile
docker用にフォルダ作って、静的ビルドしたathrillと
利用するバイナリ、aspや設定ファイル類を集めておき、そこでDockerfile作ります。FROM scratch COPY athrill2 . COPY asp . COPY memory.txt . COPY device_config.txt . CMD ["./athrill2", "-i", "-m", "memory.txt", "-d", "device_config.txt", "asp"]今更気づきましたら、CMDでオプション渡す必要ないですね。athrillだけ叩くようにして、
引数で渡す方が素直そうです。コンテナ作成
docker build -t athrill .実行
docker container run -it athrill
- 投稿日:2020-09-16T10:19:46+09:00
私がよく使うDockerコマンド一覧(コンテナ操作編)
はじめに
色々操作しているとDockerの公式マニュアル見たして覚える努力をしていたのですが、
色々なことを手を出すようになり段々覚えていられなくなってきたので、
よく使っているコマンドを一覧化して書き出してみました。コンテナ作成操作関連
以下にいくつかよく使うものを上げましたがrun optionはもっと色々あるので、
DockerのURLを参照してください。1) ホスト再起動や意図しないコンテナの停止の時に、自動的に再起動してくれるオプション
docker run --restart=always
2) コンテナのボリュームをホストにマウント
docker run -v [ホスト側のボリュームパス]:[コンテナ内のパス] [起動したいコンテナイメージ名]
3) コンテナに外部からアクセス(ポートフォワーディング)
複数指定することができますdocker run -p [外部ポート]:[コンテナポート]
コンテナへのログインやコマンド実行
1) コンテナへのログイン
docker exec -it [コンテナID or コンテナ名] /bin/bash
2) コンテナ内でのコマンド実行
docker exec [コンテナID or コンテナ名] [実行したいコマンド]
コンテナのステータス確認操作
1) 現在起動しているコンテナの一覧を表示
起動しているかどうかはSTATUSの欄がUPとなっているかを確認するdocker ps
2) 停止/起動しているコンテナの一覧を表示
※-aは--allの略docker ps -a
コンテナのログ確認
1) コンテナのログをcatで表示させるようなものです
docker logs [コンテナ名 or コンテナID]
2) ログを出力する際に時刻を付加します
docker logs -t [コンテナ名 or コンテナID]
3) ログをリアルタイムに表示し続ます
docker logs -f [コンテナ名 or コンテナID]
4) ログの最後から指定した行数を表示
docker logs --tail=[表示行数] [コンテナ名 or コンテナID]
コンテナの削除操作
1) 停止しているコンテナを削除
docker rm [コンテナ名 or コンテナID]
2) 起動しているコンテナを削除
※停止してから削除が本来は望ましいです。docker rm -rf [コンテナ名 or コンテナID]
3) 停止しているコンテナ全てを削除
-aで停止しているコンテナを全て抽出し、その中から-qでコンテナIDを抽出し削除
※起動しているコンテナについてはエラーがでて削除できないので、
その場合には起動しているコンテナを停止してから実施しましょう。docker rm $(docker ps -q -a)コンテナの停止/起動/再起動操作
1) 起動している特定のコンテナを停止
docker stop [コンテナ名 or コンテナID]
2) 停止している特定のコンテナを起動
docekr start [コンテナ名 or コンテナID]
3) 特定のコンテナを再起動
docekr restart [コンテナ名 or コンテナID]
4) 全てのコンテナを停止
-qでコンテナIDを抽出してコンテナを停止docker stop $(docker ps -q)5) 全てのコンテナを起動
-qでコンテナIDを抽出してコンテナを起動docker start $(docker ps -q)Docker操作 その他
1) 停止中のコンテナ、使用されていないネットワーク、使われていないイメージなどなど全て削除してくれる
ただし一括削除されるので実行する際には気を付けて下さい。。。docker system purne
2) 作成したコンテナもしくはイメージ名の詳細情報を表示します
docker inspect [コンテナ名 or コンテナID or イメージID]
3) コンテナ名を変更
docker rename [変更前のコンテナ名] [変更後のコンテナ名]
最後に
今回はDockerの主にコンテナの作成~削除をメインに触れました。
次記載する時はもう少し踏み込んだことを書いていきたいと思います。
- 投稿日:2020-09-16T07:48:15+09:00
OpenVINO の demo を (Google Colab|Docker) でそのまま使うだけ
Intel 入ってたら動く OpenVINO の Toolkit についてくる interactive_face_detection_demo が、そのまま動かすだけでそこそこ使えて嬉しかったのでメモです。以下 OpenVINO 2020.4 での情報になります。
Google Colab を利用する場合
Google Colab はIntel CPU を利用しているようなので、Colab 上で動かせます。
インストールはLinux 用のインストール手順を実施していくだけ、demo のビルド・実行は下記 Docker を利用する部分と同じなので、解説は割愛しています。
ただ、Colab を起動する度にインストールを待つのが面倒なのと、特性上出力ファイルがかなり大きくなるのでファイルのダウンロードが面倒なのと、そもそも Colab の CPU はそんなに早くないことが微妙なところです。Intel 入ってる環境があるなら、ローカルにファイルを直接書き込める 以下 Docker を使った方法が楽かも知れません。
ローカルに直接環境を構築する場合
既存環境と干渉するらしい記事を見たのでなんとなく避けました。インストールの項を実施していけば問題ないと思います。
Docker を利用する場合
docker run -v /c/Users/${USER}/Downloads:/Downloads -u root -it --rm openvino/ubuntu18_dev:2020.4demo を使いたいので demo 入りの _dev を使います。
ファイルをやり取りするのでダウンロードディレクトリをマウントして、インストールファイルをイジりたいので root になります。自分は Windows 10 上で動かしているので CPU only しか対応してなかったですが、対応環境では docker にオプションを渡すことで GPU などにも対応するようです。以下コンテナ内で作業
cd ${INTEL_CVSDK_DIR}/inference_engine/demos/ sed -i 's/*)/interactive_face_detection_demo)/g' CMakeLists.txt ./build_demos.shそのままだと他 demo のビルドも待たないといけないので、使いたい interactive_face_detection_demo だけに絞っています。他 demo も使ってみたい方は sed を抜いてください。
${INTEL_CVSDK_DIR}/deployment_tools/tools/model_downloader/downloader.py \ --name face-detection-adas-0001,age-gender-recognition-retail-0013,head-pose-estimation-adas-0001,emotions-recognition-retail-0003,facial-landmarks-35-adas-0002 \ --output_dir /content/model/ \ --precisions FP32interactive_face_detection_demo で使いたい学習済モデルを、付属のダウンローダーで落としてきます。face-detection などモデルがいくつもあるやつはどれを使えばいいのか迷いますが、適当に変えたら死ぬほど遅くなったりした(100倍ぐらい)ので注意です。とりあえず上記はドキュメントで指定があったものです。
/root/omz_demos_build/intel64/Release/interactive_face_detection_demo \ -i /Downloads/input.mp4 \ -m /content/model/intel/face-detection-adas-0001/FP32/face-detection-adas-0001.xml \ -m_ag /content/model/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013.xml \ -m_hp /content/model/intel/head-pose-estimation-adas-0001/FP32/head-pose-estimation-adas-0001.xml \ -m_em /content/model/intel/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.xml \ -m_lm /content/model/intel/facial-landmarks-35-adas-0002/FP32/facial-landmarks-35-adas-0002.xml \ -no_show \ -no_wait \ -async \ -o /Downloads/output.mp4オプションは他にもありますが、とりあえず上記で動画を変換できました。
- 投稿日:2020-09-16T04:09:28+09:00
Django 認証機能がうまく反映されない
はじめに
この記事ではDjango + Dockerでユーザー認証機能を盛り込む際に出たエラーの対処法について書いていきます。
ModuleNotFoundError: No module named 'allauth'
このエラー文にめちゃくちゃ悩まされました。
どうしたら良いのかわからずあきらめかけていましたが、対処法はいとも簡単でした...。まず「Docker」ファイルに次のように追記してください。
DockerfileRUN pip install django-allauth次に「requirements.txt」にも追記していきます。
requirements.txtdjango-allauth>=0.32.0最後にターミナルに次のように打ち込みます。
terminal$ docker-compose build最後にお決まりの作業をしていきます。
terminal$ docker-compose run --rm web python3 manage.py makemigrations $ docker-compose run --rm web python3 manage.py migrate $ docker-compose upこれで完了です。
最後に
このエラーに何時間もかけてしまったので、同じようにつまずいている人の助けになれば幸いです。
コマンドについてはこちらにまとめておいたので、参考になれば幸いです。
- 投稿日:2020-09-16T03:42:29+09:00
ローカル(ホストOS)のJavaプログラムからDockerコンテナ上のMySQLにアクセスする
はじめに
自分の技術スタックがあまりにもレガシーで情けなく感じ
レガシーおじさんを脱却し、技術者として再出発したく
勉強を始めました。宜しくお願いします?ということでまずはDockerを勉強することに。
構築するもの(今回のゴール)
ソフトウェア情報
OS:Windows10
Docker:19.03.12
Program:Java11
MySQL:8.0.21
Adminer:latest
WebBrowser:なんでもとりあえず今回はホストOS上の自前のJavaプログラムから
コンテナ上のDBにアクセスするところからチャレンジ。構築作業
1. Dockerコンテナ作成
DockerHubのMySQLの説明ページにあるdocker-compose.ymlをちょっとアレンジして準備。
DockerHub MySQLページ# Use root/example as user/password credentials version: '3.1' services: db: image: mysql:8.0.21 #変更 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: hoge #追加 MYSQL_USER: hoge #追加 MYSQL_PASSWORD: hoge #追加 ports: #追加 - 3306:3306 #追加 adminer: image: adminer:latest restart: always ports: - 8080:8080#が付いてるところがアレンジ部分。
MySQLイメージはlatestを指定するとバージョンがころころ変わりそうな気がしたので8.0.21を指定。
今回はコンテナ外部からアクセスするため、
適当なDBの追加とポート3306を外部公開するように設定。上記設定ファイルと同階層のフォルダで
docker-composeコマンドで起動。docker-compose upフォアグラウンド実行なのでずらずらログが出るのを見つつ、
別コンソールで立ち上がってるか確認docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0c5d267f22ee mysql:8.0.21 "docker-entrypoint.s…" 26 seconds ago Up 25 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql_db_1 258f5885810d adminer:latest "entrypoint.sh docke…" 26 seconds ago Up 25 seconds 0.0.0.0:8080->8080/tcp mysql_adminer_1(´・ω・`)おぉー
2. Adminerでテーブル、データ作成
AdminerとはPHPで作られたDB操作できるWebクライアントらしい。
MySQL、Adminerのコンテナが立ち上がってる状態で
http://localhost:8080/
にアクセスすると以下の画面が出るので
さっきのdocker-compose.ymlに記載したDB、ユーザ情報を入れる。
3. Javaプログラム作成
まずgradleにMySQLドライバの依存関係を記載。
apply plugin: 'java' apply plugin: 'application' apply plugin: 'eclipse' repositories { mavenCentral()} dependencies { compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21' testImplementation 'junit:junit:4.12' }そしてMySQLにSQLクエリを投げて結果を表示するクラスを作成。
public class DockerMySQLAccessor { public static void main(String[] args) { System.out.println("DockerコンテナのMySQLにアクセスするよ"); try(Connection con = DriverManager.getConnection( "jdbc:mysql://localhost:3306/hoge?useSSL=false", "hoge", // UserId "hoge" // Password )) { PreparedStatement pstmt = con.prepareStatement("select * from TEST_TBL"); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { System.out.printf("ID:%d, HOGE:%s \n", rs.getInt("ID"), rs.getString("HOGE")); } } catch (SQLException e) { e.printStackTrace(); } } }4. 実行
EclipseからさっきのJavaコードを実行。
さっき入れたレコードが取得できてる!
やったぜ。(´・ω・`)vまとめ
とりあえずDockerを使って手軽に仮想的なDBサーバを立ち上げ、
ローカルのプログラムからアクセスすることができた。今回はDocker触りということで
設定ほぼ丸写しでしかもいきなりdocker-composeの方を使ったけど
実際の運用ではコンテナ毎にDockerfile作ってイメージを作っていくのかな?
あと、プログラムもコンテナ上で実行し、コンテナ間で通信したいところ。
ここら辺はまた今度。謝辞
Win10にDockerを入れるの大いに参考にさせて頂きました。感謝<(_ _)>
レガシーエンジニアによるDocker入門
- 投稿日:2020-09-16T02:36:18+09:00
AmazonLinux2のDockerコンテナにPython3を入れる
# docker run docker run -it --rm amazonlinux bashコンテナ内で、
# install amazon-linux-extras install python3.8 -y # run python3.8 # venv cd /tmp python3.8 -m venv venv source venv/bin/activate
- 投稿日:2020-09-16T01:09:06+09:00
VSCodeのdevcontainerでLaravel・Docker環境を構築する
概要
VSCodeのdevcontainerを使ってLaravel環境構築を解説する記事です。
使用ツールさえ用意すれば高速で環境構築でき、Dockerを使用しているのでチームでの統一された開発環境としても使用できます。
とりあえず動かしたい人はリポジトリリンクからどうぞ。リポジトリ
https://github.com/naoyayamamoto/laravel-docker-sample
テンプレートリポジトリとして用意しているので、雛形としても使用できます。使用ツール
- Docker
- Docker-compose
- Visual Studio Code
- Visual Studio Code Remote - Containers
以上のツールを使用します。
Docker
・Visual Studio Code
についてはインストールの詳細を省きます。
Visual Studio Code Remote - Containers
についてはMicrosoft謹製のVSCodeプラグインです。リンクよりVSCodeにインストールできます。使用方法
リポジトリをVSCodeで開く
$ git clone https://github.com/naoyayamamoto/laravel-docker-sample $ code laravel-docker-sample # codeコマンドが入っていなければVSCodeでリポジトリを開いてくださいdevcontanerを使用してVSCodeを開く
- VSCodeに
Visual Studio Code Remote - Containers
が入っていれば左下にアイコンが追加されているので、それを押してダイアログを開くか、Show All Commandscmd + shift + P
でダイアログを開く。Remote-Containers: Reopen in Container
を実行すると環境の準備が始まります。- 初回はDockerの準備を行うため時間がかかりますが、2回目以降は高速で立ち上がります。
アクセス確認
http://localhost:8000
へアクセスでLaravel初期ページが表示されるはずです。解説
devcontainerを開いた際に
.devcontainer/docker-compose.yml
を元にDocker環境が構築されます。
以下のコンテナを使用しており、それぞれ解説していきます。
- nginx:alpine (web)
- mysql:8 (db)
- VSCode用にカスタマイズしたphp:7-fpm (app)
nginx:alpine (web)
- デフォルトイメージを使用
- フロントとして常に起動するので、
php artisan serve
なしでアクセス可能.devcontainer/docker/nginx/default.conf
を読み込ませ、php-fpmへ処理を流しているmysql:8 (db)
- デフォルトイメージを使用
.devcontainer/docker/mysql/my.cnf
を読み込ませている(日本語基本設定)- 環境変数
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: laravel
を設定しているので、rootパスワードなし、初期テーブルlaravel
が作成されるVSCode用にカスタマイズしたphp:7-fpm (app)
- devcontainerを開いた際の初期接続コンテナ
.devcontainer/docker/php/Dockerfile
を使用してビルドcomposer
・node
・npm
・yarn
が使用可能- php-fpmをsockで実行するために
.devcontainer/docker/php/php-fpm.d/zzz-www.conf
を読み込ませているDB_HOST: db
を設定しているので、.envでの設定よりこちらが優先されてdbコンテナに接続されますおまけ
本番環境用のDockerfile
本番を想定してビルドを行うDockerfileがリポジトリに追加しているので、カスタマイズの元として使用してください。
マルチステージビルドを使用して、jsのコンパイルとcomposerのインストールを先行して行い、最終イメージを極力小さくしています。
GithubActionsでビルドテストだけは通しています。kubernetesで使用する場合
参考までにkubernetesで使用する場合の設定です。
nginxとphpを1PODとして動かすことを想定しています。
参考deployment.yml
--- apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: default.conf: | access_log /dev/stdout main; error_log /dev/stderr warn; server { server_tokens off; sendfile on; tcp_nopush on; tcp_nodelay on; gzip on; gzip_http_version 1.0; gzip_disable "msie6"; gzip_proxied any; gzip_min_length 1024; gzip_comp_level 6; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript; open_file_cache max=100000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; listen 80; root /workspace/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index index.html index.htm index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } --- kind: Service apiVersion: v1 metadata: name: laravel-service spec: selector: app: laravel ports: - protocol: TCP port: 80 targetPort: 80 name: laravel-http --- kind: Deployment apiVersion: apps/v1 metadata: name: laravel labels: app: laravel spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: laravel template: metadata: labels: app: laravel spec: containers: - name: app image: myimage volumeMounts: - mountPath: /var/run/php-fpm name: php-fpm-socket - mountPath: /shared name: public-contents lifecycle: postStart: exec: command: ["/bin/sh", "-c", "cp -aT /workspace/public /shared"] - name: web image: nginx:alpine ports: - containerPort: 80 volumeMounts: - mountPath: /var/run/php-fpm name: php-fpm-socket - mountPath: /etc/nginx/conf.d name: nginx-conf - mountPath: /workspace/public name: public-contents volumes: - name: php-fpm-socket emptyDir: {} - name: public-contents emptyDir: {} - name: nginx-conf configMap: name: nginx-conf items: - key: default.conf path: default.conf