- 投稿日:2020-02-27T23:08:14+09:00
DockleやTrivyをCircle CIのDocker Orbと組み合わせてセキュアなコンテナを継続的に作るっ!
概要
Circle CIの「circleci/docker」というOrbを使って、以下を実践してみました!ʕ◔ϖ◔ʔ
- コンテナのビルド
- DockleとTrivyを使って、ビルドしたコンテナイメージをチェック
- OSや依存パッケージが脆弱性を含んでいないかをチェック
- ベストプラクティスに準拠したセキュアなコンテナになっているかをチェック
- 上記チェック結果が
Pass
なら、docker hub
にコンテナイメージを登録上述のサンプルを紹介しつつ、設定ファイル
.circleci/config.yml
を書く際のポイントなどを説明します。この記事を読み終わった時に、あなたにとってセキュアなコンテナのビルドがより身近なものになっていたら嬉しいなぁと思います!ゆっくり見ていってね!(o´・з・)o
読んでほしい人
Dockle
やTrivy
といったコンテナチェックツールに興味がある方- CIでのコンテナチェックに興味がある方
- CircleCIのOrbという仕組みに興味がある方
- CircleCIを含むCI/CDに知見がある方(マサカリ、お願いします!m(_ _)m)
etc..
作ったもの
まずは、実践した内容の雰囲気を掴んでいただくため、実際に作ったサンプルをごらんください。٩(ˊᗜˋ*)و
Dockle on CircleCI
Trivy on CircleCI
- GitHubリポジトリ
- CircleCIビルド結果
- try-trivy - Pipelines
- CircleCIのジョブでTrivyを実行したサンプル画像です。脆弱性無いよ!
- Docker Hubに登録したコンテナイメージ
準備
ログイン
まずは
CircleCI
やdocker hub
にログインできるようにしましょう。リントツールを使って手元でチェック
ケモケモ「よっしゃ出来た!CircleCIさん、がっつりビルド頼むわ!!」
CircleCI「記法がinvalidやで。Failやで。」
ケモケモ「Oh... (´・ω・`)」せっかく書いた
.circleci/config.yml
が、記法の間違いなどビルドできないと辛いですね。そういった問題を未然に防ぐため、コミットする前にcircleci
ツールでチェックしちゃいましょうヽ(=´▽`=)ノ。まずはインストール!
以下のコマンドで
.circleci/config.yml
が動きそうかチェックします。circleci config validate詳しくは「CircleCI のコンフィグのバリデーション」をご覧ください。
Dockle
をインストールCIで継続的に実行するのが本記事の目的ではありますが、便利なツールですし手元でコミット前にチェックするのは良い習慣ですのでインストールしましょう。
公式の Installation で各種プラットフォーム向けのインストール方法が書かれているので、好きな方法でインストールします。
使い方も簡単で、チェックしたいコンテナイメージの名前を指定して実行するだけです。めちゃシンプル!
$ dockle {YOUR_IMAGE_NAME}チェックしてくれるポイントは Checkpoint Summary にまとまってます。
Trivy
をインストールこちらもやはり手元で実行できるようにインストールしましょう。先の
Dockle
同様にGo言語製のツールですので、非常に多くのプラットフォームで実行可能です。公式の Installation を見ながらインストールします。
簡単に使えます。シンプルです。$ trivy {YOUR_IMAGE_NAME}実行結果のサンプルが Examples に多数掲載されているのでチェキです。
Orb
選びこの記事のサブテーマとしてCircle CIのOrbを積極的に使います。まずは、目的にあったOrbを CircleCI Orb Registry で探してみましょう。
今回はコンテナのビルドとプッシュをしたいので
docker
で検索してみました(上図)。CERTIFIED
マークのcircleci/docker
を使ってみましょう。Orb:
circleci/docker
https://circleci.com/orbs/registry/orb/circleci/docker
Orbの説明ページでは、Orbの機能を呼び出すための方法について以下の情報が記載されています。
- 冒頭のクイックスタートガイドで、
.circleci/config.yml
にどう書けば使い始められるか説明してる- 左のカラムに並ぶ
Usage Examples
で、需要が高そうな使い方に対してjobやworkflowの書き方を実例と共に説明してる- 左のカラムに並ぶ
Jobs
で、job名やパラメータの指定方法を説明してる- 左のカラムに並ぶ
Commands
で、command名やパラメータの指定方法を説明してるクイックスタートガイド
以下を書くだけでOrbの力を使えるようになります。パネェ₍₍ (ง ˙ω˙)ว ⁾⁾
version: 2.1 orbs: docker: circleci/docker@0.5.20Usage Examples
比較的シンプルな、以下のサンプルが参考になります。
- standard-build-and-push
- Orbの定義済みのjobである
publish
を使ったサンプル。- コンテナのbuildとpushをまとめて実施してくれる。便利。
- build-push-digest
- Orbの定義済みのcommandである
check
やbuild
を使ったサンプル。docker.hub
へのログインチェックや、build、pushなど、順を追って実施したい時に参考になる。今回は、上記
build-push-digest
をベースに作っていきます。Executor
Orbの実態は、CI/CDにすぐ組み込んで便利に使えるようCircleCIやパートナー企業が作ってくれたカスタムコンテナイメージです。
では、この
circleci/docker
のベースイメージはどんなものなのでしょう?今回のサンプルで使う「Executor - docker」でSourceを確認することでわかります。「 circleci/python 」を使っているようです。このイメージを作る
Dockerfile
は「 CircleCI-Public / circleci-dockerfiles 」にあります。追加で依存パッケージなどを使いたい場合、コンテナの素性が関係してくる場合があるので心の片隅に置いておきます。書き始めよう
かなり入念に、CircleCIの設定を書くための準備とOrbの機能を確認しました。そろそろ実際に
config.yml
を書き始めましょう。まずは
Orb
だけで書いてみるまずは
Orb
の機能だけでCIの骨子を組み立てましょう。Orb
の各種機能を呼び出す方法を整理すると、以下のような感じです。
executor
: {Orb名}/{OrbのExecutor名}
- ex)
docker/docker
- circleci/dockerのExecutors
command
: {Orb名}/{OrbのCommand名}
- ex)
docker/build
- circleci/dockerのCommands
job
: {Orb名}/{OrbのJob名}
- ex)
docker/publish
- circleci/dockerのJobs
上述のサンプルなどをベースにザクッと書いてみたのが以下です。
version: 2.1 orbs: docker: circleci/docker@0.5.20 jobs: # ビルドしたりテストしたりするジョブ。 build-and-test: executor: docker/docker steps: - setup_remote_docker - checkout # コンテナレジストリにログイン可能かチェックします。 - docker/check # コンテナをビルドします。 - docker/build: image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} # ! DockleとTrivyを使ったコンテナのtestを書く予定地です。 workflows: # ビルドしたりテストしたり、masterにマージされたらlatestコンテナを更新するワークフロー。 build-and-deploy: jobs: # masterを含む全てのブランチで実行するジョブ。 - build-and-test # masterでだけ実行されるジョブ。latestのコンテナイメージをレジストリに登録、更新する。 - docker/publish: image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} tag: 'latest' requires: - build-and-test filters: branches: only: master # gitのタグがついたらビルドとテストをして、タグ付きのコンテナをレジストリに登録するワークフロー。 deploy-tags: jobs: - build-and-test: filters: branches: ignore: /.*/ tags: only: /^v.*/ - docker/publish: image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} tag: ${CIRCLE_TAG} # 「build-and-test」のジョブが成功した時だけ、このジョブを実行するよ。 requires: - build-and-test filters: branches: ignore: /.*/ tags: only: /^v.*/なお、commandの
docker/check
は、イメージをpushするコンテナレジストリ(標準でdocker hub)にログイン可能かをチェックしてくれます。ログイン情報は、あらかじめ環境変数としてCircle CIに登録しておきます。ジョブの実行結果のログでは、ちゃんと伏せ字になりますので安心です。詳しくは プロジェクト内で環境変数を設定する を参照してください。
Dockle
とTrivy
をCIに組み込む実は
Dockle
もTrivy
も、どちらも公式でCircleCIの実行サンプルを公開しています。これらのサンプルを上述のOrbベースのCI設定に組み込みます。その際、ツールのインストールを行う箇所がそのままでは使えません。
circleci/docker
のOrbとは、executor
として使っているコンテナイメージのOSが異なるためです。それらの違いも踏まえて実際に動作することを確認した設定内容が以下です。version: 2.1 orbs: docker: circleci/docker@0.5.20 jobs: build-and-test: executor: docker/docker steps: - setup_remote_docker - checkout - docker/check - docker/build: image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} # (追加)Dockleをインストールしてスキャン実行! - run: name: Install dockle command: | VERSION=$( curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \ grep '"tag_name":' | \ sed -E 's/.*"v([^"]+)".*/\1/' ) wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz tar zxvf dockle_${VERSION}_Linux-64bit.tar.gz sudo mv dockle /usr/local/bin - run: name: Scan the image with dockle command: dockle --exit-code 1 ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_SHA1} # (追加)Trivyをインストールしてスキャン実行! - run: name: Install trivy command: | VERSION=$( curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | \ grep '"tag_name":' | \ sed -E 's/.*"v([^"]+)".*/\1/' ) wget https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz sudo mv trivy /usr/local/bin - run: name: Scan the image with trivy command: trivy --exit-code 0 --no-progress ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_SHA1} workflows: build-and-deploy: jobs: - build-and-test (後略)実際に動かしてみるとこんな感じになります。
良いですね、バッチリチェックできています。
Dockle
とTrivy
両方を使ったconfig.yml
の完成形は こちら を御覧ください。まとめ
CIを使ったコンテナの作成とレジストリへの登録は、Kubernetesクラスタへのデプロイを想定したGitOpsなどで必須となる重要なポイントだと感じています。これらの技術をProduction環境へ適用することを考えるならば、使用するコンテナ自体の脆弱性チェックはもはや避けては通れない課題です。
今回は、極力余計なものは省いて「いかに楽して脆弱性チェックの機構をCIに取り込むか」という点を意識して実践したつもりです。本記事はCircle CIを使った例でしたが、
Dockle
とTrivy
の公式ドキュメントにもあるように Travis CI など多数のCI環境で同様の「コンテナ脆弱性チェック」の仕組みを実現することが可能です。この記事が、コンテナのセキュリティを意識し始めた私のような方にとって、少しでも役立つものになっていることを願っていますʕ◔ϖ◔ʔ
おまけ
Circle CI関連の資料ばかりなのですが、有益だなぁと思ったリンクを載っけときます(ΦωΦ)
- 投稿日:2020-02-27T20:04:34+09:00
コンテナ上のpython27/pyodbcでホストのSQL Serverにアクセスする
概要
先日の以下の記事でmysqlにアクセスする方法をご紹介しましたが、
コンテナ上のpython3/mysql-connector-pythonでホストのmysqlにアクセスする
SQL serverバージョンをご紹介します。前提
ホストSQL Server
ODBC Driver 17 for SQL Server
SQLServer認証でポート1443で動作している手順
ODBCが動くDockerコンテナの作り方の記事内にある以下のリポジトリをcloneします。
https://github.com/Microsoft/mssql-docker/tree/master/oss-drivers/pyodbc> git clone https://github.com/microsoft/mssql-docker.git > cd mssql-docker/oss-drivers/pyodbc以下のツリーになっていると思います。
pyodbc ├── Dockerfile ├── README.md ├── docker-compose.yml *docker-composeで立ち上げるために追加 ├── entrypoint.sh └── sample.py *編集します。もしくは別ファイルを作ってもよいです。touch入ってませんが...Dockerfile# mssql-python-pyodbc # Python runtime with pyodbc to connect to SQL Server FROM ubuntu:16.04 # apt-get and system utilities RUN apt-get update && apt-get install -y \ curl apt-utils apt-transport-https debconf-utils gcc build-essential g++-5\ && rm -rf /var/lib/apt/lists/* # adding custom MS repository RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list # install SQL Server drivers RUN apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql unixodbc-dev # install SQL Server tools RUN apt-get update && ACCEPT_EULA=Y apt-get install -y mssql-tools RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc RUN /bin/bash -c "source ~/.bashrc" # python libraries RUN apt-get update && apt-get install -y \ python-pip python-dev python-setuptools \ --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # install necessary locales RUN apt-get update && apt-get install -y locales \ && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \ && locale-gen RUN pip install --upgrade pip # install SQL Server Python SQL Server connector module - pyodbc RUN pip install pyodbc # install additional utilities RUN apt-get update && apt-get install gettext nano vim -y # add sample code RUN mkdir /sample ADD . /sample WORKDIR /sample CMD /bin/bash ./entrypoint.shdocker-compose.yamlversion: '3' services: pyodbc: restart: always build: . container_name: 'pyodbc' working_dir: '/sample' tty: true volumes: - .:/sample extra_hosts: - "(ホストのCOMPUTERNAME):(ホストのIPアドレス)" ports: - 1443:1443sample.pyimport pyodbc server = '(ホストのIPアドレス),(ホストのSQLServer動作ポート)' username = 'sa' password = 'password' cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';database=(データベース名);UID='+username+';PWD='+password) cursor = cnxn.cursor() print ('Using the following SQL Server version:') tsql = "SELECT @@version;" with cursor.execute(tsql): rows = cursor.fetchall() for row in rows: print(str(row))> docker-compose up -d --build ... > docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2c51574bfd36 pyodbc_pyodbc "/bin/sh -c '/bin/ba…" 51 minutes ago Up 51 minutes 0.0.0.0:1443->1443/tcp pyodbc > docker exec -it 2c51574bfd36 /bin/bash $ python --version Python 2.7.12 $ python sample.py Using the following SQL Server version: (u'Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) \n\tAug 22 2017 17:04:49 \n\tCopyright (C) 2017 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 18362: ) (Hypervisor)\n', )結果
無事SQL ServerにアクセスしDB参照できました。
後日談(2/28追記内容)
ヒアドキュメントを文字列代入した時にエラー発生
変更内容
sample.pytsql = '''\ SELECT * FROM ~ INNER JOIN ~ ON '''エラー内容
$ python sample.py File "sample.py", line 17 SyntaxError: Non-ASCII character '\xe7' in file sample.py on line 18, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details File "sample.py", line 54, in <module> with cursor.execute(tsql): UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 48: ordinal not in range(128)試行した手順
以下の記事で解決しましませんでした。
http://shu223.hatenablog.com/entry/20111201/1328334689以下の記事で解決しませんでした。
https://qiita.com/chatrate/items/eb4b05cd1a6652529fd9root@2c51574bfd36:/sample# python -c "import site; print (site.getsitepackages())"
['/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']解決した手順
以下を参考にしたら解決しました。
https://kaworu.jpn.org/python/Python%E3%81%AEUnicodeDecodeError%E3%81%AE%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95
with cursor.execute(tsql.decode('utf-8')):
- 投稿日:2020-02-27T20:04:34+09:00
コンテナ上のpython/pyodbcでホストのSQL Serverにアクセスする
概要
先日の以下の記事でmysqlにアクセスする方法をご紹介しましたが、
dockerコンテナ内からホストのmysqlにアクセスする
SQL serverバージョンをご紹介します。前提
ホストSQL Server
ODBC Driver 17 for SQL Server
SQLServer認証でポート1443で動作している手順
ODBCが動くDockerコンテナの作り方の記事内にある以下のリポジトリをcloneします。
https://github.com/Microsoft/mssql-docker/tree/master/oss-drivers/pyodbc> git clone https://github.com/microsoft/mssql-docker.git > cd mssql-docker/oss-drivers/pyodbc以下のツリーになっていると思います。
pyodbc ├── Dockerfile ├── README.md ├── docker-compose.yml *docker-composeで立ち上げるために追加 ├── entrypoint.sh └── sample.py *編集します。もしくは別ファイルを作ってもよいです。touch入ってませんが...Dockerfile# mssql-python-pyodbc # Python runtime with pyodbc to connect to SQL Server FROM ubuntu:16.04 # apt-get and system utilities RUN apt-get update && apt-get install -y \ curl apt-utils apt-transport-https debconf-utils gcc build-essential g++-5\ && rm -rf /var/lib/apt/lists/* # adding custom MS repository RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list # install SQL Server drivers RUN apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql unixodbc-dev # install SQL Server tools RUN apt-get update && ACCEPT_EULA=Y apt-get install -y mssql-tools RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc RUN /bin/bash -c "source ~/.bashrc" # python libraries RUN apt-get update && apt-get install -y \ python-pip python-dev python-setuptools \ --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # install necessary locales RUN apt-get update && apt-get install -y locales \ && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \ && locale-gen RUN pip install --upgrade pip # install SQL Server Python SQL Server connector module - pyodbc RUN pip install pyodbc # install additional utilities RUN apt-get update && apt-get install gettext nano vim -y # add sample code RUN mkdir /sample ADD . /sample WORKDIR /sample CMD /bin/bash ./entrypoint.shdocker-compose.yamlversion: '3' services: pyodbc: restart: always build: . container_name: 'pyodbc' working_dir: '/sample' tty: true volumes: - .:/sample extra_hosts: - "(ホストのCOMPUTERNAME):(ホストのIPアドレス)" ports: - 1443:1443sample.pyimport pyodbc server = '(ホストのIPアドレス),(ホストのSQLServer動作ポート)' username = 'sa' password = 'password' cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';database=(データベース名);UID='+username+';PWD='+password) cursor = cnxn.cursor() print ('Using the following SQL Server version:') tsql = "SELECT @@version;" with cursor.execute(tsql): rows = cursor.fetchall() for row in rows: print(str(row))> docker-compose up -d --build ... > docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2c51574bfd36 pyodbc_pyodbc "/bin/sh -c '/bin/ba…" 51 minutes ago Up 51 minutes 0.0.0.0:1443->1443/tcp pyodbc > docker exec -it 2c51574bfd36 /bin/bash $ python --version Python 2.7.12 $ python sample.py Using the following SQL Server version: (u'Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) \n\tAug 22 2017 17:04:49 \n\tCopyright (C) 2017 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 18362: ) (Hypervisor)\n', )結果
無事SQL ServerにアクセスしDB参照できました。
後日談(2/28追記内容)
ヒアドキュメントを文字列代入した時にエラー発生
変更内容
sample.pytsql = '''\ SELECT * FROM ~ INNER JOIN ~ ON '''エラー内容
$ python sample.py File "sample.py", line 17 SyntaxError: Non-ASCII character '\xe7' in file sample.py on line 18, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details File "sample.py", line 54, in <module> with cursor.execute(tsql): UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 48: ordinal not in range(128)試行した手順
以下の記事で解決しましませんでした。
http://shu223.hatenablog.com/entry/20111201/1328334689以下の記事で解決しませんでした。
https://qiita.com/chatrate/items/eb4b05cd1a6652529fd9root@2c51574bfd36:/sample# python -c "import site; print (site.getsitepackages())"
['/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']解決した手順
以下を参考にしたら解決しました。
https://kaworu.jpn.org/python/Python%E3%81%AEUnicodeDecodeError%E3%81%AE%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95
with cursor.execute(tsql.decode('utf-8')):
- 投稿日:2020-02-27T19:41:49+09:00
Docker を用いた AOSP Android10 のビルド時間の測定結果
はじめに
AOSP Android10 全体のビルド時間を測定したので、結果を共有します。
ビルド環境には Docker (Ubuntu 18.04) を用いました。
ビルド時間短縮のポイントは、これまで AOSP のワークスペースに組み込まれてきた
ccache
が Android10 からはサポートされなくなった事 を受けて、Our binary was rather old, and for a variety of reasons we haven't kept
it updated.ビルド環境に
ccache
をインストールし、有効化する必要がありました。but if you still want to use ccache, continue setting USE_CCACHE
and also set CCACHE_EXEC to the path of your ccache executable.実行結果
クリーンビルド ビルド時間(分) ccache なし 245m ccache あり 81m
インクリメンタルビルド ビルド時間(分) ccache なし 212m ccache あり 33m 実行環境
- Azure D8 v3
- vCPU = 8 / Memory = 32GiB / Disk = 200GiB
- Docker
19.03.6
- ベースイメージは
ubuntu:18.04
- ccache
3.4.1
環境構築
ホストについて
ホスト OS は Ubuntu 18.04.4 LTS とします。また、Android のビルドには必要なパッケージが多いため、ホストに直接インストールする代わりに Docker を活用します。Ubuntu に Docker をインストールする手順やインストール後の便利な設定は、こちらをご確認ください。
Get Docker Engine >> Install using the repository
- SET UP THE REPOSITORY
- INSTALL DOCKER ENGINE
Post-installation steps for Linux >> Manage Docker as a non-root user
Post-installation steps for Linux >> Configure Docker to start on boot
Dockerfile
AOSP がサポートしている(と言っても少々古い) build/tools/docker を参考にしながら、
ベースイメージubuntu:18.04
で Android10 がビルドできるように少し修正を加えました。DockerfileFROM ubuntu:18.04 ARG userid ARG groupid ARG username RUN apt-get update && apt-get install -y \ git-core \ gnupg \ flex \ bison \ gperf \ build-essential \ zip \ curl \ zlib1g-dev \ gcc-multilib \ g++-multilib \ libc6-dev-i386 \ lib32ncurses5-dev \ x11proto-core-dev \ libx11-dev \ lib32z-dev \ ccache \ libgl1-mesa-dev \ libxml2-utils \ xsltproc \ unzip \ python \ python3-minimal \ rsync \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo \ && chmod a+x /usr/local/bin/repo RUN groupadd -g $groupid $username \ && useradd -m -u $userid -g $groupid $username \ && echo $username >/root/username \ && echo "export USER="$username >>/home/$username/.gitconfig COPY gitconfig /home/$username/.gitconfig RUN chown $userid:$groupid /home/$username/.gitconfig ENV HOME=/home/$username ENTRYPOINT chroot --userspec=$(cat /root/username):$(cat /root/username) / /bin/bash -i元 Dockerfile との差分をハイライトすると、次のようになります。
build/tools/docker/Dockerfileとの差分-FROM ubuntu:14.04 +FROM ubuntu:18.04 RUN apt-get update && apt-get install -y \ - openjdk-7-jdk + python3-minimal \ + rsync \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* - RUN curl -o jdk8.tgz https://android.googlesource.com/platform/prebuilts/jdk/jdk8/+archive/master.tar.gz \ - && tar -zxf jdk8.tgz linux-x86 \ - && mv linux-x86 /usr/lib/jvm/java-8-openjdk-amd64 \ - && rm -rf jdk8.tgz RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-download - && echo "e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5 /usr/local/bin/repo" | sha256sum --strict -c - \修正箇所について補足します。
openjdk-7-jdk / jdk8.tgz
削除
- Software requirements >> JDK によると、ビルド済 OpenJDK は既にワークスペースに組み込まれているため、古いバージョンの Android のために必要な JDK は削除しました
python3-minimal
追加
python3.x
がないと AssertionError: Could not find python binary: python3 とエラーになるため追加しましたrsync
追加
rsync
がないと FAILED: out/target/product/generic/ramdisk-debug.img とエラーになるため追加しました(ベースイメージubuntu:18.04
に含まれていませんでした)repo
のチェックサムの確認の省略
- 元コードでは
repo
の正真性をハッシュ値で確認していましたがe147f039
は古いため削除しました- その代わりに現時点の repo
2.4.1
のハッシュ値d2e17c4b
としても良かったのですが git-repo を読む限り、ここ最近頻繁に更新されていることを受け、今回はチェックそのものをやめておきますただし、十分にメンテナンスされていないように見える AOSP の Dockerfile を起点として作業をしているため、他にも既に不要なパッケージが含まれているかもしれません。今後 AOSP から新しい世代向けの Dockerfile が公開されたら、そちらに移行した方が無難です。
Docker イメ―ジのビルド
build/tools/docker/README.md を参考に Docker イメージをビルドします。
# Copy your host gitconfig, or create a stripped down version $ cp ~/.gitconfig gitconfig $ docker build --build-arg userid=$(id -u) --build-arg groupid=$(id -g) --build-arg username=$(id -un) -t android-build-bionic .ビルドされたイメージを確認します。
$ docker image list REPOSITORY TAG IMAGE ID CREATED SIZE android-build-bionic latest ff2cb9986cd7 About a minute ago 612MB
ソースコード取得
今回は Android10 Release revision 14 を題材としてビルド時間の測定することにします。
# /mnt/work/aosp をワークスペースとします $ sudo chown -R $USER:$USER /mnt $ mkdir -p /mnt/work/aosp $ cd /mnt/work/aosp $ repo init -u https://android.googlesource.com/platform/manifest -b android-10.0.0_r14$ time repo sync -j8 repo sync has finished successfully. real 51m0.159s user 133m47.445s sys 13m13.264s構築されたワークスぺースを確認します。
$ repo list | wc -l 745 $ du -sh . 90G .このように、
745
もの Git リポジトリからワークスペースが構成され、ビルド前にも関わらず90GB
もディスクを使用していることが確認できました。相変わらず巨大なプロジェクトです。ビルド
さて、いよいよビルドします。
build/tools/docker/README.md を参考に、少し手直ししながら Docker コンテナを起動します。docker-run.sh# Docker 用のキャッシュディレクトリを用意します $ mkdir -p /mnt/.cache /mnt/.ccache $ docker run -it --rm \ -v /mnt/work/aosp:/src \ -v /mnt/.cache:/mnt/.cache \ -v /mnt/.ccache:/mnt/.ccache \ -e XDG_CACHE_HOME=/mnt/.cache \ # Docker 用キャッシュディレクトリを参照します -e CCACHE_DIR=/mnt/.ccache \ # Docker 用キャッシュディレクトリを参照します -e CCACHE_COMPRESS=1 \ # キャッシュサイズの圧縮のため -e CCACHE_EXEC=/usr/bin/ccache \ # 後述 -e USE_CCACHE=1 \ # 後述 android-build-bionicこちら のコミットログによると、
ccache
を有効化するためには
-e USE_CCACHE=1
と-e CCACHE_EXEC=/usr/bin/ccache
の設定が必要でした。So if you still want to use ccache, continue setting USE_CCACHE, but also set
the CCACHE_EXEC environment variable to the path to your ccache executable.これでビルド用 Docker コンテナが起動できたはずです。
続いてccache
の有無やビルド方式の違いについて比較していきます。
なお、以降のコマンドはすべて Docker コンテナ上で実行します。クリーンビルド
中間生成物やビルド成果物を削除して、イチからビルドする方式となります。
リリースビルドの場合は、こちらになると思います。
コンフィギュレーションやビルドターゲットについては以下の公式手順を参考にしています。クリーンビルド(ccache なし)
Docker$ rm -rf out $ source build/envsetup.sh $ lunch aosp_arm-userdebug $ unset USE_CCACHE # 実験的に ccache を無効化するため $ time m #### build completed successfully (04:05:56 (hh:mm:ss)) #### real 245m55.990s user 1790m50.629s sys 97m4.830sクリーンビルド(ccache あり)
キャッシュが保存されていない環境では、以下のビルド手順を 2 回 実行して計測する必要があります。( 1 回目のビルドはキャッシュを蓄えるため )
Docker$ rm -rf out $ ccache -z # キャッシュ統計情報のクリア $ source build/envsetup.sh $ lunch aosp_arm-userdebug $ time m #### build completed successfully (01:21:53 (hh:mm:ss)) #### real 81m52.620s user 557m28.541s sys 39m36.687s
ccache
が効果的に作用したことで ビルド時間が約 1/3 に短縮されました。
この状態で、キャッシュのヒット数やヒット率などの統計情報を見てみます。ccache_統計情報の表示$ ccache -s cache directory /mnt/.ccache primary config /mnt/.ccache/ccache.conf secondary config (readonly) /etc/ccache.conf stats zero time Thu Feb 27 00:55:12 2020 cache hit (direct) 33652 cache hit (preprocessed) 325 cache miss 0 cache hit rate 100.00 % called for link 77 called for preprocessing 18 unsupported code directive 2 cleanups performed 0 files in cache 101488 cache size 3.9 GB max cache size 5.0 GB期待通り
cache hit rate 100.00 %
となっていることが確認できました。
cache hit (direct) 33652
このヒット数が妥当な数値であるかについては、ビルド対象となった C/C++ ファイルの数を調べるなどして、検証する必要があると感じています。(今回は調べ切れていません)
インクリメンタルビルド
インクリメンタルビルド(差分ビルド)は、依存関係が正しく書かれたビルドシステムを前提として、変更されたファイルとその依存ファイルがビルドされる方式です。したがって、通常クリーンビルドと比べて処理数が少なくなるため、その分高速になります。開発者がローカル環境でビルドするときは、多くの場合がこちらになると思います。
何も更新されていない場合
Docker$ ccache -z $ source build/envsetup.sh $ lunch aosp_arm-userdebug $ time m #### build completed successfully (5 seconds) #### real 0m5.080s user 0m11.956s sys 0m3.644sAndroid のビルドシステムは依存関係の記述が正しくメンテナンスされているため、差分がまったくない状態でインクリメンタルビルドをすると、あっという間に完了します。なお、このケースではコンパイルもされないため
cache hit rate 0.00 %
のままとなっていました。インクリメンタルビルド(ccache なし)
さて、今度はソースコードの更新をシミュレーションするため AOSP の一部のファイルのタイムスタンプを更新します。それによって変更されたファイルとその依存ファイルの再ビルドが実行されます。
Docker$ ccache -z $ touch external/protobuf/src/google/protobuf/* $ source build/envsetup.sh $ lunch aosp_arm-userdebug $ unset USE_CCACHE # 実験的に ccache を無効化するため $ time m #### build completed successfully (03:32:32 (hh:mm:ss)) #### real 212m31.772s user 1586m36.813s sys 69m56.492s前回の クリーンビルド(ccache なし)と比べて、わずかに短縮されていたものの、かなり時間がかかってしまいました。
インクリメンタルビルド(ccache あり)
Docker$ ccache -z $ touch external/protobuf/src/google/protobuf/* $ source build/envsetup.sh $ lunch aosp_arm-userdebug $ time m #### build completed successfully (33:53 (mm:ss)) #### real 33m53.000s user 237m48.218s sys 10m31.486sインクリメンタルビルドのおいてもやはり
ccache
は効果的で、無効時と比べて ビルド時間が約 1/6 ~ 1/7 に短縮されました。ただし、どのファイルが更新されたかで依存関係やビルド対象となるファイル数は大きく変わるため、これはあくまで一例となります。この状態で、キャッシュのヒット数やヒット率などの統計情報を見てみます。キャッシュ統計情報の表示$ ccache -s cache directory /mnt/.ccache primary config /mnt/.ccache/ccache.conf secondary config (readonly) /etc/ccache.conf stats zero time Thu Feb 27 04:28:46 2020 cache hit (direct) 1737 cache hit (preprocessed) 35 cache miss 0 cache hit rate 100.00 % called for link 8 cleanups performed 0 files in cache 101503 cache size 3.9 GB max cache size 5.0 GB今回も期待通り
cache hit rate 100.00 %
となっていることが確認出来ました。cache hit (direct) 1737
クリーンビルド(ccache あり)の時と比べて、再コンパイルの必要なファイルが少ないため、このようにヒット数自体が下がることは妥当だと思います。
おわりに
今回は Docker を用いた AOSP Android10 のビルド方法とビルド時間の測定結果についてまとめました。今後、更にビルド時間を短縮化するために、
- 更に高パフォーマンスなホストを試してみる
- より新しい https://ccache.dev (例えば
3.7+
) を試してみるなどのチャレンジをしてみても面白いと思います。
補足資料
ベンチマークが Android 4.x なので少し古い資料になりますが、Core 数や ccache と Android のビルド時間の関係について調査しているので、こちらも参考になると思います。
Accelerating Android Builds
- 投稿日:2020-02-27T18:47:30+09:00
自分なりのGoアプリケーションDockerfileのベストプラクティス
最終的に作成されるDocker Imageが軽量になること
Docker Buildにかかる時間を短縮するを目標としている
フォルダ構成
$ tree . . ├── Dockerfile ├── Makefile ├── pkg_a │ ├── pkg_a.go │ └── pkg_a_test.go ├── pkg_b │ ├── pkg_b.go │ └── pkg_b_test.go ├── go.mod ├── go.sum ├── main.go標準的なGoアプリケーションの構成
ライブラリ管理はGo Modulesを使います。Dockerfile
Dockerfileは以下のようになっています。
工夫点はコメントで番号つけてます。詳細は後述します# ① FROM golang:1.13 as builder # ② ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 WORKDIR /go/<アプリのリポジトリ名> # ③ COPY go.mod go.sum ./ RUN go mod download COPY . . # ④ RUN make # ⑤ FROM alpine RUN apk add --no-cache ca-certificates # ⑥ COPY --from=builder /go/<アプリのリポジトリ名>/app /app CMD ["/app"]説明
① multi-stage buildsを使いDocker Imageの軽量化を行う
Dockerにはmulti-stage buildsという機能があり、これを使うと1つのDockerfile内で複数の
FROM
を指定し、ビルドのベースとなるImageを分けることができます。これによりアプリケーションのビルド時のみ必要となるパッケージなどを、最終的なImageから省き、Imageサイズを削減するというのが簡単に行えます。
Goの場合、Goランタイムはビルド時のみ必要でバイナリにビルドして実行する場合は不要なので、最初のbuild用のImageベースはgolang, 最終的なImageのベースはalpineとしています。
Imageのサイズとしてはgolang:1.13が5.5GB、alpine:latestが2.68MBなので、そのままgolangを最終的なイメージベースとするより5GB以上のサイズ削減になります。
② Goのビルド設定
ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64でビルドの設定を行なっています
特に重要なのが
CGO_ENABLED=0
で静的バイナリの生成を指定してます。
これ指定しないと、alpineで実行するときにエラーになります。③ 依存ライブラリのダウンロードはなるべくキャッシュをきかせる
なるべくDocker build時にキャッシュをきかせて、ビルド速度を上げるために、リポジトリ内の全てのファイルをコピーする前に、Go Modules系のファイルだけコピーして依存ライブラリのダウンロードを行なっています。
Dockerのビルドは1行を1レイヤーとして考え、そのレイヤーで変更がなければキャッシュを利用し、変更があれば、それ以降のレイヤー全てがキャッシュ使われなくなります。
そのため実際は以下でも動くのですが、アプリのソースコードを修正しただけでも毎回依存ライブラリのダウンロードが発生してしまいます。
- COPY go.mod go.sum ./ - RUN go mod download - COPY . . - RUN make + COPY . . + RUN makeそのため、事前に
go.mod
,go.sum
だけをコピーしています。
この場合、依存ライブラリを新たに追加しない限りは、毎回キャッシュが使われてDocker buildにかかる時間を大幅に短縮できます。④ Makefile使う
RUN go build -o app
とかでもいいんですが、Makefileを用意しておくと、Dockerfileがスッキリして見栄えがよくなるかと思います。ちなみにMakefileは以下のようになっています。
all: test build setup: go get test: go test ./... build: go build -o app⑤ 最終的なImageのベースはalpineを利用する
multi-stage buildについては前述の通りです。
mulit-stage buildで最終的なImageのベースとしては、サイズを意識するならalpine一択かなと思ってます。
(運用時にコンテナ内にexecで入ってデバッグ作業とかしたいなら別のImageとかの方が良いかもですが)⑥ 別のステージで作成したアプリのバイナリファイルをコピーする
FROM golang:1.13 as builder COPY --from=builder /go/<アプリのリポジトリ名>/app /app
FROM golang:1.13 as builder
で最初のgolang:1.13を使ったbuildの間にbuilder
というaliasをつけてます。これを使って
COPY --from=builder /go/<アプリのリポジトリ名>/app /app
とすることで、golang:1.13でビルドしたアプリのバイナリファイルをalpineの中に持ってくることができます。
- 投稿日:2020-02-27T14:54:44+09:00
アプリケーション作成で詰まった箇所
執筆中
環境
Ruby 2.6.5
Rails 5.2.4
Docker 19.03.5
bundler 2.1.4
bundler問題
フラッシュメッセージ
表示される
user_sessions_controller.rbredirect_back_or_to root_url, success: 'ログインしました'表示されない
user_sessions_controller.rbredirect_to root_path, success: 'ログアウトしました'解決法
application_controller.rb# 追加 add_flash_types :danger, :success, :warning原因
調査中
そもそもadd_flash_types
の指定がないとBootstrapに対応したsuccess
info
warning
danger
の4つのキーが使用できないはずなのにredirect_back_ro_to
だと表示されるのは4つのキーがデフォルトで備わっているからなのか?文字コードがlatin1による文字化け
データベース内で文字化けするだけであって、取り出して使用する場合は文字化けしないのでとりあえず放置。
jQueryのclickイベントでdocument使用時のみ発火しない
試したこと
turbolinks
が原因か?・
Gemfile.lock
からturbolinks
削除
・application.js
から読み込み削除
・application.html.slim
から読み込み削除
参考資料・
docker-compose bundle update
・docker-compose build
・コンテナの再起動
→変わらず原因
調査中
remote: true & application.jsの//= require rails-ujs
remote: trueで送信するとrails-ujsのjQueryがなんかしてるっぽくclickイベントが使用できない。
解決法
remote: trueをやめるかclickイベントをやめる。
今回はclickイベントを使用せず実装する。ransackで関連付けしたモデルからも検索をかけたい
postsテーブルのtitle、body、tagsテーブルのtagの3つのカラムから検索をかけたい。
原因
join
関連付け
の検索ワードが出てこず若干詰まったこと解決法
訂正前
= f.search_field :title_or_body_or_cont, class: "form-control mr-sm-2", placeholder: '検索ワード'訂正後
= f.search_field :title_or_body_or_tags_tag_cont_any, class: "form-control mr-sm-2", placeholder: '検索ワード'関連付けしてあることが前提!
- 投稿日:2020-02-27T14:33:05+09:00
DockerでMySQLを立ち上げる時に文字コードを指定する
docker run --restart=always -d -e MYSQL_ROOT_PASSWORD=mysql \ -p 3306:3306 --name testdb mysql:8.0 --character-set-server=utf8mb4
- 投稿日:2020-02-27T13:17:18+09:00
Docker PHP(7.3) Apacheを使ってxdebugを動かす際にハマった
概要
- Docker/PHP公式イメージを使用してxdebugを動かそうと試みたもののうまく動かず半日ほど飛ばす。
こっちだとDocker(Nginx + php-fpm-alpine) + Laravel(6.0)をXdebugでステップ実行する瞬殺だったのに理由
- php.iniに記述したxdebugの設定が反映されない。
対応
- php.iniではなくdocker-php-ext-xdebug.iniにxdebugの設定を記述する
以下記述例
docker-php-ext-xdebug.inizend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so xdebug.remote_enable=1 xdebug.remote_autostart=1 xdebug.remote_host=docker.for.mac.host.internal xdebug.remote_handler=dbgp xdebug.remote_port=9020 xdebug.remote_log=/var/log/xdebug.log xdebug.remote_connect_back=0
- 投稿日:2020-02-27T11:53:50+09:00
PHP開発用のVisual Studioコード
私は個人的にPHPStormを開発用のメインIDEとして使用していますが、作業中の最高のIDEについて議論し始めました.VSCodeを使用する人もいれば、PHPStormを使用する人もいます。議論のため、VSCodeが完全なPHP開発IDEとして動作するようにプラグインの検索を開始しました。
While I personally use PHPStorm as my main IDE for development, we started debating the best IDE at work, some use VSCode, others use PHPStorm, because of the discussion, I started searching for plugins to make VSCode behave as a full PHP development IDE.
私の検索では、このブログ投稿に出会いました
In my search I came across this blog postこのブログを読んで、私はインストールしました:
Reading this blog, I installed:残りについては、
settings.json
の指示に従っただけです。
For the rest, I just followed the instructions for thesettings.json
私が行った唯一の追加手順は、常にdockerを使用し、マシンにローカルにPHPがインストールされていないため、「組み込みのphp検証」を無効にすることです。
The only extra step I took, is disabling thebuilt-in php validation
because I always use docker, and don´t have PHP installed locally on my machine.VscodeおよびDocker用にXdebugを構成する
私は通常、開発環境にdockerを使用するため、xdebugの設定には時間がかかりました。さまざまなブログやstackoverflowの質問にアクセスした後、これが私の「launch.json」設定です
Since I usually make use of docker for my development enviroment, configuring xdebug took me a while, after visiting various blogs and stackoverflow questions, this is mylaunch.json
config{ "name": "Listen for XDebug", "type": "php", "request": "launch", "port": 9000, "log": true, "externalConsole": false, "pathMappings": { "/application": "${workspaceFolder}" }, "ignore": [ "**/vendor/**/*.php" ] }fuxideブログ投稿へのクレジット。これは設定の参照に使用します。
Credits to fuxide blog post, that I use for reference for the config.何らかの理由で変数の監視は機能しませんが、これらはデバッガの一般的なセクションに表示されます
For some reason the variable watches don´t work, but these are visible in the general section of the debuggerCLIを使用するのが好きなので、gitプラグインをインストールしたくありませんでしたが、職場の友人からの推奨に従って、gitkraken を試してみます。
I did not want to install any git plugin, because I like using the CLI, but per recommendation from my friends at work, I´ll give gitkraken a try.世の中の読者にとって、どのIDEが開発にお気に入りですか?
For the readers out there, what IDE is your favorite for development?
- 投稿日:2020-02-27T03:28:12+09:00
Docker Toolboxを使ってDockerでLaravel開発環境を作ってみる
はじめに
今までVagrant+VirtualBox、XAMPP、Laravel Homesteadと開発環境を構築してきましたが、現在本格的にエンジニア志望の身の上であるということと、友人がDockerで環境構築をしたという話を聞いたので私もこれからの開発環境をDockerに絞ってやっていこうと思い今回挑戦してみましたので備忘録として書きます。
一応Githubにも慣れる目的でpushしてありますが、基本的には後述の参考記事の手順通りにやったことをWindows10 Homeでやるために私がしたことを追記して書いたようになりますので、作ったDocker環境は同じです。
https://github.com/shitikamiyako/Docker-Laravel-Demo
最初に行っておきたいこと
Dockerを使うならMacかWindowsならせめてWindows10 Proを使うことをおすすめします、Homeだとまーややこしいというより、Dockerを使うメリットの半分くらいなくなっている気がしなくもないです。
Linuxに明るい人だとLinuxでやる人もいるそうな。構築する環境
windows10 home(Ryzen 5 3600)
docker v18.06.1-ce(途中でv19.03.1にアップデートします)
VirtualBox 6.0.16Dockerとは?
私が語るよりも詳しいことは下記の記事をご覧になってください。
さくらナレッジ様より Docker入門(第一回)~Dockerとは何か、何が良いのか~
Dockerでプログラマが最低限知るべきことが、最速でわかるチュートリアル
さくらナレッジさんの記事より引用させていただくと、Dockerとは簡潔に言うと以下のような仕組みです。
Dockerは、Linuxのコンテナ技術を使ったもので、よく仮想マシンと比較されます。VirtualBoxなどの仮想マシンでは、ホストマシン上でハイパーバイザを利用しゲストOSを動かし、その上でミドルウェアなどを動かします。それに対し、コンテナはホストマシンのカーネルを利用し、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができます。そのため、軽量で高速に起動、停止などが可能です。
イメージとコンテナについて十全に理解するにはLinux及びDockerについてもう少し深く勉強する必要があるので、あくまで今の私の感覚で話をすると、イメージはコンテナを作る材料のようなものだと思うとわかりやすいかもしれません。
例えば、今回はLaravelをDockerに導入するためにNginx(サーバー) 、PHP(言語)、 MySQL(データベース)
の3つを用意しないといけないのですけど、Dockerの場合これを用意するにはまず各々のイメージをDocker Hubのレポジトリから引っ張ってこないといけない(pullするという)ので、まずそれを行います。
そしてそれを使用するために用意してきたイメージから各コンテナを作ることになります。
こうすることで各コンテナがサーバー・PHP実行環境・データベースの役割を持つのであとはPHP実行環境にLaravelをインストールしてしまえばLaravel環境の完成ということになります。
よく言われるDockerの利点の1つがここで、開発環境によって使うイメージを組み合わせることで容易に異なる環境を構築することができます。
例えば上記の例においてもこれとは別にデータベースをMySQLではなくMariaDBにしたLaravel環境を用意したいということであれば、MariaDBイメージを用意すればいいということになりますね。Dockerインストール
DockerはMacを使ってると話が早いみたいなのですが、そうでなければ早くも詰まるポイントその1です。
通常、Macの場合であればDocker for Macと呼ばれるインストーラーからインストールできるのですがWindowsの場合だとかなりややこしいです。
まず、使用しているWindowsがWindows10 Proの64bit版であるかどうかで分岐します。
そうであるなら、Docker for Windowsというインストーラーが使えるのでこれを使いましょう。
違う場合、つまり今回のパターンだと残念ながらそのままだとDockerは使えずDocker Toolboxというものを使い、VirtualBox下でDockerを使うことになります。
仮想マシンを使わないのがDockerの利点の1つのはずなので虚無の気持ちを覚えますが、受け入れましょう。まずGithubから最新版をダウンロードします。
DockerToolboxしかし、ここでも詰まるポイントがあってCPUがAMD製つまりRyzenを使用されてる場合はなんとバージョンによってインストールの際弾かれてしまう場合があります。
私はRyzenを使っているので見事に弾かれました。
その場合は、バージョンを下げたもので試してみてください、私は冒頭のバージョンで成功した後、最新版にアップグレードすることで事なきことを得ました。
さて、ToolboxをインストールするとDocker QuickStart Terminalというものがあるはずなのでそれを起動してください。
インストールの際にVirtual BoxやGitなどWindows10 HomeでDockerを使うために必要なものを同時にインストールするかどうか聞かれますが、各々で必要なければチェックを外しましょう。無事にこのようにクジラが出てきたらDockerのインストール完了です。
以後Dockerを起動する際もDocker QuickStart Terminalから起動できます。
あと、これも詰まるポイントの1つなのですが仮想環境を使うためには
Hyper-vの機能を有効にしないといけません。
これはCPUがIntel製かAMD製か、さらにWindowsがProかHomeかで、もっというとマザーボードがどこのものかで有効にする手段が違うのですが、このあたりはお使いの環境を調べてHyper-v 有効というキーワードでググっていただければ。
私の場合は、BIOSの設定から有効にしないといけませんでした。開発環境の構築をしていく
docker-composeでLaravelの開発環境を整える方法とその解説
(以下参考記事1と呼称させて頂きます。)詳しいことは上記の記事を参照して頂いた方がわかりやすく話も早いのですが、今回の場合はWindows10 Homeでの導入になりますので、私からも順を追って話をさせていただきます。
1.Virtual Boxのポートフォワーディングの確認
まずは、Windows10 Homeの場合必ず確認しなればならないのがここです。
これ、今冷静に考えればWindows10 HomeでのDockerの使用はVirtual Boxをかませてその中の仮想マシン(Linux)で動かすわけですから、当然仮想マシン側のポートもちゃんと設定してあげないとlocalhostすらままならないんですけど、なぜか私はそれに気づかず8時間くらい溶かしてました。
こんな人は他にはいないと思いますけど、後々あれ? とならないようにまずこちらから設定しましょう。Virtual Boxを起動して、Dockerで使用している仮想マシンを選択して設定のところをクリックします。
どれを使用しているんだ? となる方はDockerを起動してdocker-machine ls
とコマンドプロンプトで打つと、起動している仮想マシンの詳細が出るのでそこのNAMEの部分がDockerで使用されている仮想マシンの名前になりますので確認してみてください。
導入直後のままならおそらくdefaultという名前のはずです。さて、設定をクリックしたあとはネットワークの項目を選択、高度と書かれているところのプルダウンメニューを表示させると下記のようにポートフォワーディングの項目が出るのでそこをクリックしましょう。
すると下記のような画面が出てくるので、右側のプラスマークのアイコンからポートの設定ができます。
名前・ホストIP(ローカル環境なので、127.0.0.1)、ホストポート、ゲストポートを設定します。
このあと、Dockerの方でもホスト⇒ゲストとポートの設定のをするのですが、ややこしいことにWindows10 HomeでのDocker利用はWindows⇒Virtual Box⇒Docker
つまり
大本のホスト⇒Dockerから見たホスト(Windowsから見るとゲスト)⇒ゲスト
といったような構造になっているため、Docker側でVirtual Box⇒Dockerでのポートの設定をしても、Windows⇒Virtual Box側でポートを通してやらないと暖簾に腕押しということになってしまうのです。
ネットワークの知識に少し明るいとこういうところは当然なのかもしれないですが、私みたいなまだまだビギナーという人には落とし穴になりがちだと思うので最初に確認して頂きたいです。2.docker-compose.ymlの記述
参考記事1から引用させていただくと
docker-compose.ymlには、yaml形式で、複数のコンテナで構成されるサービスを構築・実行する手順等を記述します。
それぞれのコンテナについて、イメージ作成時にベースにするDockerイメージやDockerfileの指定・ホスト側からDockerコンテナ側へのポートフォワーディングの指定・Dockerコンテナに共有する(ホスト側の)ファイル群の指定などを定義することができます。ということになります。
つまり、このコンテナ(役割)を使った環境を作りますよという設計図のようなものですね。
なお、今回私は以下のようなディレクトリ構造で構築しましたので以後の説明はこれに沿っているものと考えてください。・docker-compose-laravel(ルートフォルダ)
├── demo-docker-app(Laravel)
├── docker
│ └── web
│ └── default.conf
│ └── php
│ └── Dockerfile
├── docker-compose.yml
└── index.html
└── index.phpディレクトリの構築が終わったらdocker-compose.ymlに以下のように記述します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html上記はNginxを実行するコンテナを定義しています。
versionはdocker-compose.yml
のファイルフォーマットのバージョン指定。serviceはコンテナの名前の定義で、インテンドが1つ下がった部分が実行するコンテナの定義となります。
なので、docker-compose.yml
記述でのインテンド上げ下げは正確に行わければいけないので注意しましょう、インテンドが間違っていると必ずエラーが出てうまくいきません。imageはDockerイメージの指定になります。
このコンテナではNginxを使いたいのでバージョンを含めて上記のように指定します。portsは前述の通り、ポートフォワーディングの設定になります。
1で設定したものと同じになるように設定しましょう。
ちなみにホストのポート:ゲストのポートという記述になりますが、ゲスト側のポートの下2桁の00は省略します。volumesはホスト・コンテナ間でのファイル共有の指定で、ホスト側のパス:コンテナ側のパスの形式で記述します。
Homestead使ったことがある人ならわかると思うのですが、要はホスト側で編集した内容等がゲスト側にも反映されるように同期をとるようなものです。
いちいちゲスト側の環境でコード書いたりしなくてもいいようにすると思っていただければ。
./docker/web/default.conf:/etc/nginx/conf.d/default.conf
と書いてありますがこれは
ホスト側のパス:ゲスト側のパス
という記述になります。
.:/var/www/html
つまり上記の場合はホスト側のルートフォルダの内容はゲスト側の
/var/www/html
部分に反省されていますよということになります。また、volumesを設定することファイルやディレクトリは、永続化(コンテナを削除してもホスト側にファイルやディレクトリが残る)させることができるようです。
3.default.confの記述
このファイルはNginxの設定ファイルとなります。
以下のように基準してください。server { listen 80; root /var/www/html; index index.html; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; }listenはリクエストを受け付けるIPアドレスやポート番号の設定です。
上記の場合はすべてのIPアドレスの80番ポートでリクエストを受け付けるということになります。
root, indexでは、それぞれ、ドキュメントルートのディレクトリ・インデックスとして使われるファイル名を定義します。
indexの部分は先程の通りでindexは適当な確認用のindex.html
作っておいてそれを設定してください。
access_log, error_logはそれぞれのログ出力先の設定となります。4.Nginxの動作確認
ここまでの工程でローカルでWebサーバーを立ち上げる準備ができたので立ち上げてみます。
ディレクトリをルートフォルダに移して以下のコマンドを実行します。docker-compose up -dこのコマンドは
docker-compose.yml
の記述どおりにコンテナを作って、起動してくださいという意味になります。
-d
のオプションはバックグラウンドでコンテナを実行するためのコマンドになります。
これがない場合は、up
で実行された時にコンテナはすぐに終了してしまいます。無事に作成・開始が成功すると以下のように表示されます。
Creating network "docker-compose-laravel_default" with the default driver Creating docker-compose-laravel_web_1 ... doneブラウザでhttp://localhost:8000 にアクセスすると、index.htmlが表示されます。
8000の部分は設定したポート番号に合わせてください。5.PHP実行環境の準備
NginxでWebサーバーを立ち上げたので今度はそこでPHPを動作できるようにします。
そのためにはPHP-FPMというのものを使うのですが、このあたりの詳しいことは参考記事1で紹介されている、以下の記事をご覧になってください。私も今読んでいます。
nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築するさて、コンテナを追加するのでdocker-compose.ymlを編集していきます。
以下の通りに記述してみてください。version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: image: php:7.2-fpm volumes: - .:/var/www/htmlservicesの項目に、appを追加します。
そして、webの項目にdepends_onを追加してそこにappを指定しておきます。
これはサービスの依存関係を表すもので、今回はNginxがPHPに依存をしているということになります。
この定義によって、Dockerはコンテナの起動時にサービスの依存関係に基づいてコンテナを起動するようになるので、PHPコンテナが起動した後にNginxコンテナが起動するということになります。
あとの項目はNginxのときと同じですね、イメージを指定してファイル共有の定義をします。次に、PHPが動くようにNginxの設定を変更します。
以下のように記述してください。server { listen 80; root /var/www/html; index index.php index.html index.htm; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }indexの項目を見るとindex.phpとindex.htmが追加されています。
先程はindex.htmlをインデックスページとして設定しましたが、このよう複数設定すると先に記述があるファイルから優先してインデックスページに設定されます。
今回はphpを実行したいのでindex.phpを先頭に記述することになります。locationの項目はURIごとにどのファイルを配信するのか設定する項目です。
最初のlocationではURIのパスにファイルがあるかどうかを確認し、なかった場合はディレクトリがあるかを確認し、いずれもなかった場合はindex.phpを返すという意味になります。
次のlocationではNginxがPHP-FPMにリクエストを渡すための設定をしています。
詳しいことは先述の記事を確認してください。ここまでが終わったら動作確認です。
index.htmlと同じように適当な確認用のindex.phpを作成して、配置してください。
そのあとは先程と同じようにdocker-compose up -d
を行います。
もし、先程実行したまま作業を続けている場合は、docker-compose down
というコンテナを停止・削除するコマンドを実行してから行ってください。
実行するとhttp://localhost:8000 でindex.phpが表示されます。
phpinfo();
のコマンドを仕込んでおくとPHPが実行されているかよりわかりやすくなると思います。6.MySQLコンテナを用意する
最後にDBとしてMySQLを準備をします。
docker-compose.ymlを編集してMySQLのコンテナを定義します。version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: image: php:7.2-fpm volumes: - .:/var/www/html depends_on: - mysql mysql: image: mysql:5.7 environment: MYSQL_DATABASE: sample MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:ここまで来るとservicesはweb、app、mysqlで構成されたサービスだということがわかりやすくなりますね。
environmentはMySQLコンテナでの環境変数の設定です。
Laravelでの.envファイルにあるMySQLの項目と同じですね。
またここでのvolumesはmysql-dataをサービス内で共通化して、他のコンテナからも参照できるようにするための設定のようです。ここまで終わったら動作確認をしましょう。
upしたままならdownをしてから、もう一度docker-compose up -d
を行います。
そうしたら以下のコマンドでMySQLのコンテナに入ることができます。docker-compose exec mysql bashコンテナに入るとあとは通常のMySQLの操作と同じなので
mysql -h localhost -u -pでログインしてください、ユーザー名とパスワードは先程設定したものを入力します。
MySQLに入ったらshow databases;
でデータベースを確認し、docker-compose.ymlで定義したデータベースが作成できているか確認してください。7.Laravelのインストール
では、いよいよLaravelのインストールになります。
Composerがどうのとかそういうのはここでは割愛します。
一応私も手前味噌ですがLaravel導入に関して備忘録を残してありますので、よろしければそちらをご覧になってください。まず、Dockerfileというものを作成します。
これはビルドするイメージの構成の定義です。
docker-compose.ymlで定義したのでは? と思った方、私も思いました。
どうやらこちらは必要なパッケージその他を指定した上でイメージをどう構成するかということを定義するもののようです。
先程だけだとPHPしか入りませんが、今度はComposerなどを入れたいのでそのためにDockerfileで指示書を書くというイメージでしょうか。FROM php:7.2-fpm # install composer RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer RUN apt-get update \ && apt-get install -y \ git \ zip \ unzip \ vim RUN apt-get update \ && apt-get install -y libpq-dev \ && docker-php-ext-install pdo_mysql pdo_pgsql WORKDIR /var/www/htmlこれが今回のDockerfileです。
FROMでイメージ(厳密にはDocker Hubレジストリで公開されているベース)を指定し、
curlコマンドでcomposerをインストール、さらにapt-getコマンドでgit、zip、unzip、vimをインストール、最後にdocker-php-ext-installコマンドでPDOをインストールするという意味になります。
RUNでこれらをDockerイメージのビルド時にコンテナで実行するように定義しています。
WORKDIRはRUNなどの命令が実行される際のディレクトリを指定します。Dockerfileを作ったら、docker-compose.ymlのPHPの部分、つまりappの部分をDockerfileに基づくように修正します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: build: ./docker/php volumes: - .:/var/www/html depends_on: - mysql mysql: image: mysql:5.7 environment: MYSQL_DATABASE: sample MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:imageの部分をbuildにしてDockerfileがあるディレクトリを指定します。
こうすることでDockerfileに基づいてイメージを作成し、appコンテナ(PHPコンテナ)が出来上がるということになります。あとはLaravelを入れるだけです。
毎度のようにdocker-compose up -d
を行い、今度はPHPコンテナに入りたいのでdocker-compose exec app bash
を行って以下のコマンドを実行してLaravelをインストールします。composer create-project --prefer-dist laravel/laravel プロジェクト名無事にLaravelのインストールが完了したら.envファイルのMySQLの項目をdocker-compose.ymlで定義したものに合わせて設定してください。
DB_HOSTの項目はmysqlと指定します。最後にNginxの設定をLaravelに合わせたものに修正します。
以下の通りです。server { listen 80; root /var/www/html/my-laravel-app/public; index index.php index.html index.htm; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }rootの部分をLaravelのpubilcフォルダに合わせることでここがルートディレクトリになります。
ここまで終わったら動作確認です。
まず、docker-compose down
を実行して、docker-compose up -d
、docker-compose exec app bash
でPHPコンテナに入ってマイグレーションを行います。
あとは以下のようにLaravelプロジェクトのフォルダにディレクトリを移してmigrateするだけですね。cd プロジェクト名 php artisan migrateマイグレーションが正常に行われたことを確認したら、再度docker-compose down
を実行して、
docker-compose up -d`を行い、http://localhost:8000 を確認してください。
Laravelのウェルカムページが表示できたら無事終了です、お疲れさまでした。おまけ
Docker Toolboxのアップグレードについてはこちらを参照してください。
参考:Windows10 Homeで導入したdockerを最新にアップデートする方法
手順としてはアップグレードしたいバージョンのDocker ToolBoxをダウンロードしてきて、導入の時と同じことをするだけです。
Select Componentsは導入と同じように入れる必要のないもの(この場合はアップグレードする必要のないもの)はチェックを外し、次のSelect Additional Tasksもすべてチェックを外します。インストールが終わったら
docker -v
でバージョンを確認して、バージョンが上がったことを確認したらdocker-machine upgrade default
で仮想マシン側のDockerもバージョンを上げておきます。(厳密にはdocker-machineは仮想マシン側でのDockerのホストを生成して管理しているものみたいです)
これでアップグレードは完了です。あとがき
最初はGit経由でやろうとしていましたが、ポートフォワーディングの罠にハマりうまく行かないと思い込んでしまったので今回Dockerfileとdocker-compose.ymlで1からDocker環境を構築してみました。
災い転じて福となすとばかりに、とてもわかりやすい記事がありましたのでそれを参照しながら、うまく行かない原因がポートフォワーディングの罠だったことなど色々発見しながらDockerにおける環境構築の基本を学習できたのでとても有意義でした。
でも、フォロワーさんに「Linuxを扱えるようにならないとね?(威圧)」というありがたくも耳が痛すぎるリプライを頂いて、それに納得・承知をした上でやっぱり言わせてください。Docker環境を整備したい! という方はできればMacも導入してください。
Linux、いずれは向き合わないといけないなぁ。