- 投稿日:2020-06-03T23:07:32+09:00
コンテナ内の仮想インタフェースがホスト側のどの仮想インタフェースに対応するかを調べる
Dockerの場合はホスト側でこのワンライナー叩けばいけます。
ip link | grep -E "^`sudo docker exec container_name cat /sys/class/net/eth0/iflink`:"コンテナの外でパケットをキャプチャしたい場合など、ホスト側のインタフェース名はランダムで生成されるため、対応関係がわかりにくいです。
それを調べる方法が上記のコマンドです。ホスト側の仮想インタフェースのうち、ifindex値がコンテナ内の仮想インタフェースのiflink値と同じものが対応するインタフェースになります。
LXCでも仕組みは同じだと思うので、iflink値を元にして探せると思います。(未検証)
- 投稿日:2020-06-03T21:27:57+09:00
OpenCVのDockerfile作ってみた
はじめに
Dockerfile作る練習とたまたま作る機会があったので、こちらで供養します。
フルオプションではないです。。。そんなことはできないです。
ただし、opencv_contlibはインストールしています。修正点などあればお気軽に。
Dockerfile
FROM nvidia/cuda:10.1-cudnn7-devel-ubuntu16.04 ENV DEBIAN_FRONTEND=noninteractive ARG python_version="3.7.3" ARG version="4.2.0" # install tools RUN apt-get update && apt-get -y upgrade &&\ apt-get install -y --no-install-recommends \ vim unzip byobu wget tree git cmake\ && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* # install python RUN apt-get update && apt-get install -y zlib1g-dev libssl-dev libffi-dev build-essential \ checkinstall libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev \ libgdbm-dev libc6-dev libbz2-dev &&\ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN mkdir /workspace WORKDIR /workspace RUN wget -c https://www.python.org/ftp/python/${python_version}/Python-${python_version}.tgz RUN tar zxvf Python-${python_version}.tgz && cd Python-${python_version} &&\ ./configure --enable-optimizations --enable-shared CFLAGS=-fPIC &&\ make -j8 && make install && ldconfig RUN rm Python-${python_version}.tgz RUN pip3 install -U pip RUN pip3 install -U setuptools # install opencv RUN pip3 install -U numpy RUN apt-get update && apt-get install -y --no-install-recommends \ gcc g++ libpng-dev libjpeg-dev libopenexr-dev libtiff-dev libwebp-dev \ libgtk-3-dev &&\ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN wget -c https://github.com/opencv/opencv/archive/${version}.tar.gz RUN tar -zxvf ${version}.tar.gz RUN rm ${version}.tar.gz RUN mkdir /workspace/opencv-${version}/build ## opencv_contrib WORKDIR /workspace RUN wget -c https://github.com/opencv/opencv_contrib/archive/${version}.tar.gz RUN tar -zxvf ${version}.tar.gz WORKDIR /workspace/opencv-${version}/build ## make opencv RUN cmake -OPENCV_EXTRA_MODULES_PATH=/workspace/opencv_contrib-${version}/modules .. RUN make -j8 && make install && ldconfig RUN rm /workspace/${version}.tar.gz WORKDIR /workspace動作確認は、こちらのサイトのコードで確認しました。
- 投稿日:2020-06-03T19:37:11+09:00
【AWS】ECSリポジトリにローカルのDockerをプッシュできないときの対処方法
環境
Docker 19.03.8
macOS 10.15.4IAMユーザーの作成
IAMユーザーを作成し、その後にアクセスキーを設定します。
terminal$ aws configure AWS Access Key ID [****************]: (credencialsのAccess key ID) AWS Secret Access Key [****************]: (credencialsのSecret access key) Default region name [ap-northeast-1]: ap-northeast-1 Default output format [json]: jsonそして
$ aws configure list
を実行します。terminal$ aws configure list Name Value Type Location ---- ----- ---- -------- profile <not set> None None access_key (credencialsのAccess key ID) env secret_key (credencialsのSecret access key) env region ap-northeast-1 config-file ~/.aws/config※しかしこのときにセキュリティ的に伏せていますが
$ aws configure
と$ aws configure list
のアクセスキー及び、シークレットアクセスキーが一致していない前提です認証トークンを取得し、レジストリに対して Docker クライアントを認証しようとするものの...
terminal$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin (アカウントID).dkr.ecr.ap-northeast-1.amazonaws.com An error occurred (UnrecognizedClientException) when calling the GetAuthorizationToken operation: The security token included in the request is invalid.このエラーの内容は認証情報周りの設定に問題があることが原因だと言うことがわかりました。アクセスキーとシークレットアクセスキーがenvになっているのでおそらくどこかで環境変数にアクセスキーとシークレットアクセスキーを設定していると考えました。
.bash_profileを確認する
.bash_profileの中を確認してみます。
terminal$ open -a TextEdit ~/.bash_profile
$ aws configure list
で確認されたアクセスキーとシークレットアクセスキーの末尾と一致するアクセスキーとシークレットアクセスキーが表示されましたので削除します。ターミナルを閉じて再度開いてから
$ aws configure list
を実行すると.bash_profileのアクセスキーとシークレットアクセスキーが優先され、IAMユーザー認証情報が実行できなかった場合にこれでエラーが解消されます。それ以外のアクセスキーとシークレットアクセスキーが優先されていた場合は...
下記のコマンドを実行し一度リセットします。
terminal$ mv ~/.aws/credentials /tmp/credentials.bak $ mv ~/.aws/config /tmp/config.bak # credentialとconfigを削除するコマンドそして一度ターミナルを閉じてから再度開いて
$ aws configure
を実行して再設定する方法もあります。以上が【ECSリポジトリにローカルのDockerをプッシュできないときの対処方法】になります^_^
- 投稿日:2020-06-03T18:50:45+09:00
WSL2を有効にしてwindows dockerとVMware15.5.5を共存させる
概要
docker起動したままVMwareを使おうとしたとき、「Hyper-V または Device/Credential Guard が有効な状態で~」と言われてVMwareが起動しなかったが、以下の記事を見つけたが、複数の対応が必要で解決まで辿った道のりを記録します。
「VMware Workstation/Player」が「Hyper-V」と共存可能に ~v15.5.5が正式公開
https://forest.watch.impress.co.jp/docs/news/1255681.html
※2020年5月27日投稿の記事環境により対応内容が違うと思いますので、エラーメッセージから対応内容を参考にするまでにして下さい。
私自身分からない事も多いですが、また迷うと勿体ない為分かっていることだけ記事にしておきます。
最終環境
docker desktop 2.3.0.3(45519)
windows10 version2004
VMware15.5.5各エラー(または要件)対応方法
windows10のバージョンが1904
2020/06/03時点では
下記サイトにいって
https://www.microsoft.com/ja-jp/software-download/windows10
アップデート実行ファイル(Windows10Upgrade9252.exe)をダウンロードしてを実行する
※こちらの環境では約3時間くらいdockerでWSL 2 is not installedと表示される。
PowerShellを管理者で起動する
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
wsl --set-default-version 2が実行できない①
PS C:\WINDOWS\system32> wsl --set-default-version 2 wsl : 用語 'wsl' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。Microsoft Store からlinux ディストリビューションを Windows 10 にセットアップする
wsl --set-default-version 2が実行できない②
PS C:\WINDOWS\system32> wsl --set-default-version 2 WSL 2 を実行するには、カーネル コンポーネントの更新が必要です。詳細については https://aka.ms/wsl2kernel を参照してください下記サイトにいって
https://aka.ms/wsl2kernel
wsl_update_x64.msiをダウンロードして実行(1分もかからない)解決
PS C:\WINDOWS\system32> wsl --set-default-version 2 WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください参考
参考にさせて頂きました。
WSL 2 対応 Docker Desktop for Windowsを使うための手順
https://qiita.com/zembutsu/items/22a5cae1d13df0d04e7bWSL2を操作しようとすると「カーネル コンポーネントの更新が必要です」と表示される
https://qiita.com/quzq/items/3de595e14426d0352fc4
- 投稿日:2020-06-03T18:24:19+09:00
Dockerとvagrantを一緒に使ってVagrant upができなくなった話
問題
vagrant upするとこのようなエラーがでました。
Stderr: VBoxManage.exe: error: VMMR0_DO_NEM_INIT_VM failed: VERR_NEM_MISSING_KERNEL_API_2 (VERR_NEM_MISSING_KERNEL_API_2).
Dockerとvagrantは一緒に使ってしまうとエラーの原因になるようです。
解決方
① windowsの検索画面からWindowsの機能の有効かまたは無効化 をクリック
・Hyper-T
・Containers
のチェックを外す② コマンドプロンプトを起動
bcdedit コマンドを実行
bcdedit /set hypervisorlaunchtype off コマンドを実行おわりに
これを行うと次はDockerのほうでエラーがでるので設定を戻さなければなりませんでした。二つを使い分けるのはあまりよくないかもしれないですね。どうなんでしょうか
- 投稿日:2020-06-03T18:01:50+09:00
超基礎からの 速習 Docker (5)
本稿は、Christffer Noring さん (@chris_noring) の Learn Docker, from the beginning, part V を翻訳し、分かりやすいように少しだけ追記、サンプルコードの実行上の補足等を行ったものです。シリーズ翻訳の意図については 超基礎からの 速習 Docker (1) の冒頭に掲載しています。併せてご参照くださいませ。
Twitter をフォローして、トピックへのあなたの問い合わせやご質問、提案を頂けるとハッピーです。
超基礎からの 速習 Docker シリーズ一覧
この文章はシリーズの一つです:
- 超基礎からの 速習 Docker (1)
- なぜ Docker なのか、コンテナーやイメージ、Dockerfile の基本コンセプトの解説、もちろん、それらを管理するのに必要なコマンド群もカバーしています。
- 超基礎からの 速習 Docker (2)
- Volume を用いたデータの永続化や、開発環境の Volume 化を通じて、開発をより手軽なものにします。
- 超基礎からの 速習 Docker (3)
- データベースをコンテナ化し、レガシーなやり方及び新しいやり方である Network を用いて他のコンテナから連絡可能にします。
- 超基礎からの 速習 Docker (4)
- Docker Compose を用いた複数サービスの管理方法を解説します(その1)
- 超基礎からの 速習 Docker (5)
- 僕らはいまここ
パート IV で紹介したプロジェクトを引き続き用いて、Docker Compose の機能と、必要になるだろう全てをカバーする本質にせまったプロジェクトのビルドについてのショーケースをお見せします。
このパートでカバーするのは:
- 環境変数 前回のパートでカバーしていますので、多くはどのようにそれらを Docker Compose にセットするかについてです。
- Volume 以前の記事でカバーしていますが、その利用法と Docker Compose でどう使うかについて説明します。
- Network と データベース ついにデータベースと Network をカバーします。このパートは少しトリッキーですが、多分、全てを説明することに成功したと思います。
もし、どこかのポイントで混乱を感じたなら、この記事の元になっているリポジトリーは以下にあります。
https://github.com/softchris/docker-compose-experiments
注釈
混乱も何も、パート IV 以降、Docker Compose 解説に用いられていたプログラムは、この GitHub にあるコードが初公開です(お待たせしました)。以降、こちらのコードを用いて確認していきましょう。パート IV のお浚いにも使えるかと思います。リソース
Docker を使う事、コンテナー化は、一枚岩をマイクロサービスに分解していくことです。このシリーズのいたるところで僕らは Docker やそのコマンド体系をマスターするために学ぶことになります。そうすれば、きっと君は自作のコンテナーをプロダクション環境で使いたくなるでしょう。その環境は大抵クラウド上にあります。十分な Docker 経験を積んだと思ったなら、次のリンクで Docker をクラウドでどのように活用できるか、ご確認してみると良いと思います。
- Azure 無料アカウントのサインアップ プライベート レジストリのようなクラウドのコンテナーを使うには、無料 Azure アカウントが必要でしょう。
- クラウドのコンテナー クラウドのコンテナーについて他に知っておくべきことについて網羅する概要ページです。
- 自作コンテナーをクラウドにデプロイ 今の Docker スキルをレバレッジしてクラウド上でサービスを動かすことがいかに簡単かを示すチュートリアル。
- コンテナー レジストリの作成 自作 Docker イメージを Docker Hub に入れられますが、クラウドのコンテナー レジストリも可能です。自作イメージをどこかにストアして、一瞬でレジストリから実際のサービスをできるようにすることは凄くないですか?
環境変数
以前の記事で示したものの一つに、環境変数の指定方法があります。変数は
Dockerfile
に設定できますが、コマンドラインで設定でき、よって、Docker Compose の中でも可能であり、つまり、docker-compose.yaml
内では:docker-compose.yamlversion: '3' services: product-service: build: context: ./product-service ports: - "8000:3000" environment: - test=testvalue inventory-service: build: context: ./inventory-service ports: - "8001:3000"上記では、
-test=testvalue
で環境変数の定義、変数 test の値testvalue
を行っています。product-service ディレクトリにある app.js ファイル の中で、process.env.test から読み込むことで、簡単にテストできます。
他のテスト方法は、Docker Compose を実行して、どんな環境変数が有効か、以下のように query することです:
% docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 72a2c0c98dda docker-compose-experiments_product-service "docker-entrypoint.s…" 6 minutes ago Up 56 seconds 0.0.0.0:8000->3000/tcp docker-compose-experiments_product-service_1 211d3dc8584a docker-compose-experiments_inventory-service "npm start" 6 minutes ago Up 56 seconds 0.0.0.0:8001->3000/tcp docker-compose-experiments_inventory-service_1 fb095493518d docker-compose-experiments_db "docker-entrypoint.s…" 6 minutes ago Up 56 seconds 0.0.0.0:8002->3306/tcp docker-compose-experiments_db_1 % docker exec docker-compose-experiments_product-service_1 env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=72a2c0c98dda test=testvalue DATABASE_PASSWORD=complexpassword DATABASE_HOST=db NODE_VERSION=14.1.0 YARN_VERSION=1.22.4 PORT=3000 HOME=/rootまず最初に、Docker Compose セッションのコンテナーを
docker-compose ps
とすることで取得します。ついで、docker exec [container name] env
として、環境変数をリストします。他のやり方としてはdocker exec -it [container name] bash
を実行してコンテナーに入り、環境変数を表示させます。Docker Compose で環境変数を管理するやり方はわずかしかありません。他に何ができるかについては、official doc を参照ください。訳注
もし、docker ps
で何も出てこなければ、まだコンテナーを起動していません。以下の手順でコンテナーを起動します。
- GitHub から clone します。Git をインストールして、こんな感じで clone します。
- 取得した
docker-compose-experiments/product-service
フォルダに移動。npm install --save-dev nodemon
として nodemon をインストールする。- (Windows のみ)wait-for-it.sh ファイルを CRLF から LF に変換する。これにはいろんなやり方があります。適当なエディタで変換しても OK です。CRLF ってなんじゃいって言う方はこちら。
docker-compose up -d
などとしてコンテナーを起動します。Volume
以前のパートで Volume についてカバーして分かった凄いやり方は:
- 永続的スペースを作る ログファイルや データベースと言った、コンテナーの再起動後も残しておきたいものに最適です。
- 開発環境を Volume 上に展開する このようにするメリットは、コンテナー開始後のコードの変更を、リビルドやコンテナーの再起動なしに反映する、言わばリアルタイム サーバーにすることができる点です。
「永続的スペース」は、persistent space を翻訳したものですが、要はそこに書いてある通り、コンテナーの終了後も残せるということをイメージして「永続的」と言っています。
永続的スペースを作る
Docker Compose で Volume をどのように扱うか見て行きましょう。
docker-compose.yamlversion: '3' services: product-service: build: context: ./product-service ports: - "8000:3000" environment: - test=testvalue inventory-service: build: context: ./inventory-service ports: - "8001:3000" volumes: - my-volume:/var/lib/data volumes: my-volume:ファイル最後の volumes コマンドで volume を作成しています。2つ目の行では、
my-volume
と言う名前を与えています。さらに、inventory-service の個所で、作成された volume の参照と、終了しても永続化したい Volume のディレクリ、var/lib/data
へのマッピングを行っています。正しくマップされている状態を見てみましょう。% docker exec -it 211 bash root@211d3dc8584a:/app# ls Dockerfile README.md app.js node_modules package-lock.json package.json root@211d3dc8584a:/app# cd .. root@211d3dc8584a:/# ls app bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@211d3dc8584a:/# cd var/lib/ root@211d3dc8584a:/var/lib# ls apt data dpkg git misc pam python systemd ucf root@211d3dc8584a:/var/lib# cd data root@211d3dc8584a:/var/lib/data# lsご覧になっている通り、上記コマンド、
docker exec
でコンテナーに入り、次にマッピングされたディレクトリに移動しています。ありました。すごいねVolume マッピングがちゃんと動いているかどうか確認するために、ディレクトリにファイルを作りましょう:
echo persist > persist.log
上記コマンドは、persist と言う内容で
persist.log
を作っています。派手なものではありませんが、コンテナーの再起動後でも探すことのできるファイルを作成します。さあ、コンテナーを終了できます。次に、便利な Volume コマンドをお浚いしましょう:
docker volume ls
% docker volume ls DRIVER VOLUME NAME local ce29ece31b9a806b4f8f5527ca914c6b695fc28ebea294f61b1fa916b2988bd1 local docker-compose-experiments_my-volume上記は 現在マウントされている Volume すべてがリストされます。作成された Volume docker-compose-experiments_my-volume も見えます。
更なる詳細へダイブしましょう:
docker volume inspect docker-compose-experiments_my-volume
% docker volume inspect docker-compose-experiments_my-volume [ { "CreatedAt": "2020-06-02T16:49:32Z", "Driver": "local", "Labels": { "com.docker.compose.project": "docker-compose-experiments", "com.docker.compose.version": "1.25.5", "com.docker.compose.volume": "my-volume" }, "Mountpoint": "/var/lib/docker/volumes/docker-compose-experiments_my-volume/_data", "Name": "docker-compose-experiments_my-volume", "Options": null, "Scope": "local" } ]OK、これは
Moutpoint
と言った Volume の詳細を教えてくれます。Mountpoint
は、Volume マッピング ディレクトリに書き込んだ時、どこにあるファイル群が永続化されるのかが分かります。それではコンテナーを終了させましょう。
docker-compose down
Volume はまだあるはず。それでは再度コンテナーを開始しましょう:
docker-compose up-d
コンテナーに入って、persist.log ファイルがあるかどうか見てみましょう。% docker exec -it 648 bash root@648f3b1ac8f1:/app# ls Dockerfile README.md app.js node_modules package-lock.json package.json root@648f3b1ac8f1:/app# cd .. root@648f3b1ac8f1:/# ls app bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@648f3b1ac8f1:/# cd var/ root@648f3b1ac8f1:/var# ls backups cache lib local lock log mail opt run spool tmp root@648f3b1ac8f1:/var# cd lib root@648f3b1ac8f1:/var/lib# ls apt data dpkg git misc pam python systemd ucf root@648f3b1ac8f1:/var/lib# cd data root@648f3b1ac8f1:/var/lib/data# ls persist.log root@648f3b1ac8f1:/var/lib/data# more persist.log persist root@648f3b1ac8f1:/var/lib/data#イェーイ、動いていますね。
カレント ディレクトリを Volume にする
OK、新しい Volume を追加して、僕らのコンピュータのディレクトリと、それと同期するべきコンテナー内の場所を指定する必要があります。
docker-compose.yaml
は次のようになっています:docker-compose.yamlversion: '3' services: product-service: build: context: ./product-service ports: - "8000:3000" environment: - test=testvalue volumes: - type: bind source: ./product-service target: /app inventory-service: build: context: ./inventory-service ports: - "8001:3000" volumes: - my-volume:/var/lib/data volumes: my-volume:新しく追加になったのは、
product-service
です。Volume コマンドを一つのエントリーで設定できるようになったのが分かります。では、エントリーをブレイク・ダウンしてみましょう:
- type: bind bind mount と呼ばれる、ローカル ディレクトリとコンテナー間のファイル同期によりフィットした Volume を作ります。
- source 単純に君のファイル群がどこにあるか。ここでは
./product-service
が指定されています。このディレクトリにあるファイルに変更があれば、Docker は直ちにそれを拾い上げます。- target コンテナーのディレクトリです。source と target は同期状態となります。source が変われば、同じ変更が target にも起きます。
Network とデータベース
OK、それではこれがこの記事でカバーしようとしていたことのラスト パートです。データベースを開始しましょう。多くの主要なベンダーは SQL Server、Postgres、MuSQL などなどのような Docker Image を持っています。このことは、データベースを起動、実行するのに、ビルド ステップは必要ないことを意味します。しかし、環境変数ややりとりするための Port のオープンといった設定は必要です。僕らのソリューションに MySQL データベースを追加しましょう。dockder-compose.yml ファイルで行います。
データベースの追加
データベースを docker-compose.yml に追加することは、凡そ、既成イメージを追加することです。幸運なことに、MySQL は Ready-made イメージが提供されています。追加するには、ただ サービス以下に別のエントリーを追加するだけです。こんな具合に:
docker-compose.ymlproduct-db: image: mysql environment: - MYSQL_ROOT_PASSWORD=complexpassword ports: - 8002:3306ブレイクダウンしていきましょう:
product-db
は僕らが選んだ新しいサービス エントリーの名前です。image
はビルドの代わりの新しいコマンドです。イメージがすでにビルドされている時に使います。ほとんどのデータベースについて可能です。enviroment
多くのデータベースはユーザー名、パスワード、もしかするとデータベースの名前(データベースの種類で変わります)といった、接続のためのいくつかの変数を設定する必要があるでしょう。今回のケースでは、MYSQL_ROOT_PASSWORD が設定され、root ユーザーのパスワードが何か、MySQL インスタンスに伝えています。アクセス レベルを変えたユーザーをいくつか作ることを考慮するべきでしょう。ports
オープンするポートを列挙します。これがデータベースと話す入り口になります。8002:3306
とすれば、コンテナーの Port は 3306 が外部ポート 8002 にマッピングされます。データベースと残りのサービスを起動、実行しましょう:
% docker-compose up -d Creating network "docker-compose-experiments_products" with the default driver Creating network "docker-compose-experiments_default" with the default driver Creating docker-compose-experiments_inventory-service_1 ... done Creating docker-compose-experiments_db_1 ... done Creating docker-compose-experiments_product-service_1 ... done確認してみましょう:
docker-compose ps
またはdocker ps
% docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------------- docker-compose-experiments_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:8002->3306/tcp docker-compose-experiments_inventory-service_1 npm start Up 0.0.0.0:8001->3000/tcp docker-compose-experiments_product-service_1 docker-entrypoint.sh /wait ... Up 0.0.0.0:8000->3000/tcp
良さそうですね。データベース
docker-compose-experiments_db_1
は Port 8002 で起動、実行しているように見えます。次にデータベースに接続してみましょう。以下のコマンドはデータベースに接続します。指を交差させてmysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8002訳注
パート3で述べた通り、Windows では 0.0.0.0 にアクセスすることはできないため、docker exec -it docker-compose-experiments_db_1 bash
などとして、コンテナー内にログインし、コンテナー内でmysql -uroot -pcomplexpassword
すれば良いかな、と思います。勝者は・・:
% mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8002 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.6.48 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>素晴らしい!次はデータベースに接続するように更新しましょう。
データベースに接続する
データベースに接続するには、主に 3つの方法があります。
- すでに試した通り、
mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8002
とするdocker exec -it [name of container] bash
を用いてコンテナーに入り、コンテナーの中でmysql
をタイプする。- 次章でお見せする通り、
npm library mysql
を用いて、アプリから接続する3つめの選択にフォーカスして、アプリからデータベースに接続します。データベースとアプリは異なるコンテナーに存在します。どのように接続するのでしょう?その答えは:
- 同じ Network にいる必要がある 二つのコンテナーがお互い話せるようにするには、同じ Network にいる必要があります。
- データベースが Ready 状態である必要がある データベースの起動には時間がかかるし、アプリがデータベースと話せるようになるためには、データベースを正常に起動する必要があります。私が方法を見つけるまで、これは楽しく/興味深く/ツライことでした。だから安心して。僕らは成功します
- connection object を作る
product-service
のapp.js
で coonection object をセットアップします。最初のアイテムから始めましょう。どのようにデータベースとコンテナーを同じネットワークに入れるのでしょう。簡単です。Network を作って、それぞれのコンテナーを同じネットワークに配置します。
docker-compose.yaml
の中を見てみましょう:docker-compose.yaml# excerpt from docker-compose.yaml networks: products:各サービスにネットワークをアサインします。こんな風に:
docker-compose.yaml# excerpt from docker-compose.yaml services: some-service: networks: - products今や第二の弾丸ポイントです。データベースが初期化処理を終わっているとどうやって分かるのでしょう?ええっと、
depends_on
というプロパティがあります。あるコンテナーが他のコンテナーが初期化処理を終えるまで待つことを設定できます。こんな風に設定します:docker-compose.yaml# excerpt from docker-compose.yaml services: some-service: depends_on: db db: image: mysqlすばらしい、解決した?いやいやいや、落ち着いてくれ。
Docker Compose ver.2 では、サービス ヘルスを確認する代替案が使われます。もし良いヘルスなら、コンテナーを起動します。こんな感じです:
depends_on: db: condition: service_healthyこれは、データベースが完全に初期化するまで待つことを意味します。しかし、これが最後ではありません。ver.3 では、このオプションはなくなりました。ここに、それがなぜなのかについて書かれた doc ページがあります → control startup and shutdown order。要点は、データベースが実行中で接続準備可能であることを確認することは我々の責任だということです。Docker はこの件について、いくつかスクリプトを提案しています。
これら全てのスクリプトが、特定の
host
とport
を監視し、返信があり次第アプリを起動する、という動作をします。そのように動作するためには何をする必要があるでしょう?wait-for-it
というスクリプトを選択し、やるべきことをリストしましょう:
- コピー スクリプトをサービス コンテナーに配置します。
- 実行権限 スクリプトに実行権限を付与する。
- 設定 docker ファイルに、スクリプトが実行できえるよう、データベース ホストとポートを設定し、スクリプトが OK のとき一度サービスが実行するように設定する。
GitHub からスクリプトをコピーして、
product-service
ディレクトリに入れるところから始めましょう。こんな感じに見えるでしょう:/product-service wait-for-it.sh Dockerfile app.js package.jsonDockerfile を開いて、以下を追加しましょう。
DockerfileFROM node:latest WORKDIR /app ENV PORT=3000 COPY . . RUN npm install EXPOSE $PORT COPY wait-for-it.sh /wait-for-it.sh RUN chmod +x /wait-for-it.sh上記は、
wait-for-it.sh
ファイルをコンテナーにコピーして、下の行で実行権限を与えています。注目するべき点は、Dockerfile から ENTRYPOINT も削除されていることです。代わりに、コンテナーにdocker-compose.yaml
ファイルからスタートを指示します。docker-compose.yaml# excerpt from docker-compose.yaml services: product-service: command: ["/wait-for-it.sh", "db:8002", "--", "npm", "start"] db: # definition of db service below上記で、wait-for-it.sh ファイルを実行するようにし、
db:8002
をパラメータに与え、期待するレスポンスがあった後に、サービスがスタートアップするよう、npm start
が実行されています。素晴らしいものに見えますね、上手く動くでしょうか?全部を公開するために、フルバージョンの
docker-compose.yaml
を見ましょう:docker-compose.yamlversion: '3.3' services: product-service: depends_on: - "db" build: context: ./product-service command: ["/wait-for-it.sh", "db:8002", "--", "npm", "start"] ports: - "8000:3000" environment: - test=testvalue - DATABASE_PASSWORD=complexpassword - DATABASE_HOST=db volumes: - type: bind source: ./product-service target: /app networks: - products db: build: ./product-db restart: always environment: - "MYSQL_ROOT_PASSWORD=complexpassword" - "MYSQL_DATABASE=Products" ports: - "8002:3306" networks: - products inventory-service: build: context: ./inventory-service ports: - "8001:3000" volumes: - my-volume:/var/lib/data volumes: my-volume: networks: products:OK、復習しましょう。
product-service
とdb
が Networkproducts
に配置されていて、wait-for-it.sh
スクリプトがダウンロードされ、アプリが起動する前に実行され、データベースの実行準備が整い次第、反応するようにデータベースのホストとポートを監視します。やることが一つ残っています。product-service
のapp.js
ファイルを調整します。ファイルを開きましょう:app.jsconst express = require('express') const mysql = require('mysql'); const app = express() const port = process.env.PORT || 3000; const test = process.env.test; let attempts = 0; const seconds = 1000; function connect() { attempts++; console.log('password', process.env.DATABASE_PASSWORD); console.log('host', process.env.DATABASE_HOST); console.log(`attempting to connect to DB time: ${attempts}`); const con = mysql.createConnection({ host: process.env.DATABASE_HOST, user: "root", password: process.env.DATABASE_PASSWORD, database: 'Products' }); con.connect(function (err) { if (err) { console.log("Error", err); setTimeout(connect, 30 * seconds); } else { console.log('CONNECTED!'); } }); conn.on('error', function(err) { if(err) { console.log('shit happened :)'); connect() } }); } connect(); app.get('/', (req, res) => res.send(`Hello product service, changed ${test}`)) app.listen(port, () => console.log(`Example app listening on port ${port}!`))引数に object を持つ
createConnection()
を呼び出して接続を作るconnect()
メソッドが定義されていることが分かると思います。引数にはhost
、user
、password
、database
が必要です。これは完全に合理的に見えます。setTimeout()
を呼び出して、次の接続まで 30秒間隔をあけるロジックが僅かにconnect()
メソッドにあります。今回はwait-for-it.sh
を使うため、この機能は必要ないのですが、接続を得るためにアプリケーション単体でも頼れるようにします。しかし、conn.on('error')
も呼び出す理由は、接続を失う可能性があるからです。お行儀のよいコードにするべきであり、その接続を取り戻すことができるようにする必要があります。ところで、僕らのパワーですべてを終えたけど、
Dockerfile
が変わったことを教えてあげなければいけません。docker-compose build
で全てをリビルドし、その後すべてを実行しましょう:
docker-compose up
すると・・・
ありました。ヒューストン、接続があります。または、私の友人バーニーがこうするみたいに:
訳注
すみません、なんのジョークかさっぱり分かりませんでした・・データベースの設定 ―― 構造とデータを与える
OK、もしかすると、service db をどう作るのか考えているかも?
docker-compose.yaml
の一部はこんな感じになっています:docker-compose.yamldb: build: ./product-db restart: always environment: - "MYSQL_ROOT_PASSWORD=complexpassword" - "MYSQL_DATABASE=Products" ports: - "8002:3306" networks: - products特に build を見て欲しい。この記事の最初で、データベースの Ready-made イメージを引っ張ってこれると説明しました。このステートメントは正しいですが、この Dockerfile を作ることによって、データベースを指定するだけでなく、データベースの構造とシード データを作るといったコマンドを実行することもできるのです。
product-db
ディレクトリを見てみましょう:/product-db Dockerfile init.sqlOK、
Dockerfile
があります。最初にそれをみてみましょう:DockerfileFROM mysql:5.6 ADD init.sql /docker-entrypoint-initdb.d
init.sql
がコピーされ、docker-entroypoint-initdb.d
にリネームすることを設定しています。これは最初に実行されます。素晴らしい、init.sql
の中身はどうでしょうか:init.sqlCREATE DATABASE IF NOT EXISTS Products; # create tables here # add seed data inserts here今回、多くを持っていませんが、絶対拡張できることが分かると思います。それが重要です。
サマリー
このシリーズについて一周まわって、最初からすべてを説明しました。基本的な概念、主要コマンド、Volume とデータベースの扱い方、そして、Docker Compose のより効果的に使う方法などです。このシリーズは今後も継続して Docker の世界へ深く深く進んでいきますが、少しでもお役に立てれば幸いです。ここまで読んでくれてありがとうございました。
- 投稿日:2020-06-03T16:27:09+09:00
Dockerfileで 環境構築を自動化
はじめに
本記事は動画( https://youtu.be/RYXtItghA14 )で説明に使用している
スライドを記事化したものです。動画と合わせて御覧ください。
※記事化する際に補足説明を加筆しており、内容は動画のスライドと異なります。
※本記事の内容は2020年3月時点の内容となります。OSやミドルウェア、Dockerのバージョンが異なることで記載通りの内容で完了しない場合があります。
Dockerfileで出来る事
- イメージのダウンロード
- コンテナイメージ内でのシェルコマンド実行
- ローカルファイルをコンテナイメージ内への転送
- 実行ユーザ切り替え
Dockerfileで出来ない事
- デーモン(サービス)の起動
- Webアプリ環境構築でのDBへの初期DB構築などは出来ない
Dokcerコマンド一覧
コマンド 概要 FROM イメージを指定 LABEL メタデータの設定 ENV 環境変数を設定 RUN コンテナ内でコマンドを実行 COPY ファイル、ディレクトリをローカル→コンテナ、コンテナ→ローカルにコピーする ADD ファイル、ディレクトリをローカル→コンテナに追加。.tarファイルをアンパックできる CMD RUNのパラメータを設定。RUN実行後にクリアされる WORKDIR 作業ディレクトリを指定 ARG docker buildコマンド時の引数定義 ENTRYPOINT コンテナにコマンドと引数を提供 SHELL コンテナ内の実行シェルの指定と設定 USER ユーザの切替
実行コマンド
docker build -t [イメージタグ] .
動画で使ったDockerfile
# centos7のイメージを利用する FROM centos:7 LABEL maintainer=Takemi SHELL ["/bin/bash", "-o", "pipefail", "-c"]" # 累積アップデートの実行 RUN yum -y upgrade #rootパスワード設定 RUN echo "root:docker123" | chpasswd; #takemiユーザが存在していない場合ユーザ追加する RUN echo 'make user takemi' RUN adduser -m takemi;echo "takemi:takemi123" | chpasswd; #sshのインストール RUN yum install -y openssh-server RUN systemctl enable sshd #Apacheのインストール RUN yum install -y httpd RUN systemctl enable httpd #MariaDBのインストール RUN curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash RUN yum install -y MariaDB-server RUN systemctl enable mariadb RUN yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm RUN yum -y install --enablerepo=remi,remi-php73 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-mysqlnd php-pecl-mysql #DocumentRoot作成 RUN mkdir /var/www/webapp RUN chown takemi /var/www/webapp RUN chgrp takemi /var/www/webapp RUN chmod 774 /var/www/webapp RUN gpasswd -a apache takemi USER takemi COPY index.html /var/www/webapp/ USER root RUN chmod 772 /var/www/webapp/index.html #RUN systemctl restart httpd
- 投稿日:2020-06-03T12:31:22+09:00
DockerでつまづくLaravel Dusk何なのお前
色々事情があってブラウザテストすることになったんですよ。
そう言えばLaravelには「Dusk」っていうイカしたブラウザテストユニットがあったなとか思い出して、試しに使ってみました。
https://readouble.com/laravel/5.5/ja/dusk.html↑のドキュメント通り、duskをインストールし、動かしてみたら
# php artisan dusk Cannot load Xdebug - it was already loaded Cannot load Xdebug - it was already loaded PHPUnit 6.5.14 by Sebastian Bergmann and contributors. E 1 / 1 (100%) Time: 1.29 seconds, Memory: 16.00MB There was 1 error: 1) Tests\Browser\ExampleTest::testBasicExample Facebook\WebDriver\Exception\UnknownServerException: unknown error: cannot find Chrome binary (Driver info: chromedriver=2.35.528139 (47ead77cb35ad2a9a83248b292151462a66cd881),platform=Linux 4.19.76-linuxkit x86_64)は? chromeのバイナリがないだと?
いい忘れてたけど、環境
OS/ミドルウェア/FW バージョン CentOS 7.5 Apache 2.4.6 php 7.2.28 Laravel 5.5.46 これをDockerで組んでます。
chromeを入れてみる
んじゃ、素直に入れてみますかね。
CentOSはepel入れるとchromiumを入れることができるようになります。$ yum install -y epel-release $ yum install -y chromiumよしよし、うごかしてみっかー。んー、なかなか応答が返ってこないなー、、、お、今度は
/session
がダメとか言ってくるなー。1) Tests\Browser\AdminTest::testTop Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {"desiredCapabilities":{"browserName":"chrome","platform":"ANY","chromeOptions":{"binary":"","args":["--disable-gpu","--headless"]}}}--no-sandbox を入れてみる
なんか調べども調べども
seleniumコンテナ入れろ
みたいなのばっかなんですよね。なんか負けたような気がするじゃないですか。気の所為でしょうけど。んで、たどり着いたのはこちら。
Laravel DuskをDockerコンテナ内で起動するまでなんと、
--no-sandbox
フラグを付けるだけだと……!?
DuskTestCase.php
に追記しましょ。DuskTestCase.phpprotected function driver() { $options = (new ChromeOptions)->addArguments([ '--disable-gpu', '--headless', '--no-sandbox', //追記 ]); return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options ) ); }よし、これで動いた!