20200603のdockerに関する記事は9件です。

コンテナ内の仮想インタフェースがホスト側のどの仮想インタフェースに対応するかを調べる

Dockerの場合はホスト側でこのワンライナー叩けばいけます。

ip link | grep -E "^`sudo docker exec container_name cat /sys/class/net/eth0/iflink`:"

コンテナの外でパケットをキャプチャしたい場合など、ホスト側のインタフェース名はランダムで生成されるため、対応関係がわかりにくいです。
それを調べる方法が上記のコマンドです。

ホスト側の仮想インタフェースのうち、ifindex値がコンテナ内の仮想インタフェースのiflink値と同じものが対応するインタフェースになります。
LXCでも仕組みは同じだと思うので、iflink値を元にして探せると思います。(未検証)

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

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

動作確認は、こちらのサイトのコードで確認しました。

なんとなくのブログ:OpenCVが4.0になっていたのでcontribも含めてコンパイルしてみる。

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

【AWS】ECSリポジトリにローカルのDockerをプッシュできないときの対処方法

環境

Docker 19.03.8
macOS 10.15.4

IAMユーザーの作成

IAMユーザーを作成し、その後にアクセスキーを設定します。

terminal
$ aws configure
AWS Access Key ID [****************]: (credencialsAccess key ID)
AWS Secret Access Key [****************]: (credencialsSecret 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     (credencialsAccess key ID)      env    
secret_key     (credencialsSecret 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をプッシュできないときの対処方法】になります^_^

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

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 にセットアップする

参考
https://qiita.com/zembutsu/items/22a5cae1d13df0d04e7b#linux-%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97

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/22a5cae1d13df0d04e7b

WSL2を操作しようとすると「カーネル コンポーネントの更新が必要です」と表示される
https://qiita.com/quzq/items/3de595e14426d0352fc4

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

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のほうでエラーがでるので設定を戻さなければなりませんでした。二つを使い分けるのはあまりよくないかもしれないですね。どうなんでしょうか

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

超基礎からの 速習 Docker (5)

Whale, Docker

本稿は、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.yaml
version: '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 で何も出てこなければ、まだコンテナーを起動していません。以下の手順でコンテナーを起動します。

  1. GitHub から clone します。Git をインストールして、こんな感じで clone します。
  2. 取得した docker-compose-experiments/product-service フォルダに移動。
  3. npm install --save-dev nodemon として nodemon をインストールする。
  4. (Windows のみ)wait-for-it.sh ファイルを CRLF から LF に変換する。これにはいろんなやり方があります。適当なエディタで変換しても OK です。CRLF ってなんじゃいって言う方はこちら
  5. docker-compose up -d などとしてコンテナーを起動します。

Volume

以前のパートで Volume についてカバーして分かった凄いやり方は:

  • 永続的スペースを作る ログファイルや データベースと言った、コンテナーの再起動後も残しておきたいものに最適です。
  • 開発環境を Volume 上に展開する このようにするメリットは、コンテナー開始後のコードの変更を、リビルドやコンテナーの再起動なしに反映する、言わばリアルタイム サーバーにすることができる点です。

「永続的スペース」は、persistent space を翻訳したものですが、要はそこに書いてある通り、コンテナーの終了後も残せるということをイメージして「永続的」と言っています。

永続的スペースを作る

Docker Compose で Volume をどのように扱うか見て行きましょう。

docker-compose.yaml
version: '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 でコンテナーに入り、次にマッピングされたディレクトリに移動しています。ありました。すごいね:smiley:

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.yaml
version: '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.yml
product-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 で起動、実行しているように見えます。次にデータベースに接続してみましょう。以下のコマンドはデータベースに接続します。指を交差させて:wink:

mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8002

finger crossed

訳注
パート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 状態である必要がある データベースの起動には時間がかかるし、アプリがデータベースと話せるようになるためには、データベースを正常に起動する必要があります。私が方法を見つけるまで、これは楽しく/興味深く/ツライことでした。だから安心して。僕らは成功します:grinning:
  • connection object を作る product-serviceapp.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

すばらしい、解決した?いやいやいや、落ち着いてくれ。

wait

Docker Compose ver.2 では、サービス ヘルスを確認する代替案が使われます。もし良いヘルスなら、コンテナーを起動します。こんな感じです:

depends_on:
 db:
   condition: service_healthy

これは、データベースが完全に初期化するまで待つことを意味します。しかし、これが最後ではありません。ver.3 では、このオプションはなくなりました。ここに、それがなぜなのかについて書かれた doc ページがあります → control startup and shutdown order。要点は、データベースが実行中で接続準備可能であることを確認することは我々の責任だということです。Docker はこの件について、いくつかスクリプトを提案しています。

これら全てのスクリプトが、特定の hostport を監視し、返信があり次第アプリを起動する、という動作をします。そのように動作するためには何をする必要があるでしょう?wait-for-it というスクリプトを選択し、やるべきことをリストしましょう:

  • コピー スクリプトをサービス コンテナーに配置します。
  • 実行権限 スクリプトに実行権限を付与する。
  • 設定 docker ファイルに、スクリプトが実行できえるよう、データベース ホストとポートを設定し、スクリプトが OK のとき一度サービスが実行するように設定する。

GitHub からスクリプトをコピーして、product-service ディレクトリに入れるところから始めましょう。こんな感じに見えるでしょう:

/product-service
  wait-for-it.sh
  Dockerfile
  app.js
  package.json

Dockerfile を開いて、以下を追加しましょう。

Dockerfile
FROM 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.yaml
version: '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-servicedb が Network products に配置されていて、wait-for-it.sh スクリプトがダウンロードされ、アプリが起動する前に実行され、データベースの実行準備が整い次第、反応するようにデータベースのホストとポートを監視します。やることが一つ残っています。product-serviceapp.js ファイルを調整します。ファイルを開きましょう:

app.js
const 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() メソッドが定義されていることが分かると思います。引数には hostuserpassworddatabase が必要です。これは完全に合理的に見えます。setTimeout() を呼び出して、次の接続まで 30秒間隔をあけるロジックが僅かに connect() メソッドにあります。今回は wait-for-it.sh を使うため、この機能は必要ないのですが、接続を得るためにアプリケーション単体でも頼れるようにします。しかし、conn.on('error') も呼び出す理由は、接続を失う可能性があるからです。お行儀のよいコードにするべきであり、その接続を取り戻すことができるようにする必要があります。

ところで、僕らのパワーですべてを終えたけど、Dockerfile が変わったことを教えてあげなければいけません。docker-compose build で全てをリビルドし、その後すべてを実行しましょう:
docker-compose up

すると・・・

run docker-compose up

ありました。ヒューストン、接続があります。または、私の友人バーニーがこうするみたいに:

my friend Barney

訳注
すみません、なんのジョークかさっぱり分かりませんでした・・

データベースの設定 ―― 構造とデータを与える

OK、もしかすると、service db をどう作るのか考えているかも?docker-compose.yaml の一部はこんな感じになっています:

docker-compose.yaml
db:
  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.sql

OK、Dockerfile があります。最初にそれをみてみましょう:

Dockerfile
FROM mysql:5.6

ADD init.sql /docker-entrypoint-initdb.d

init.sql がコピーされ、docker-entroypoint-initdb.d にリネームすることを設定しています。これは最初に実行されます。素晴らしい、init.sql の中身はどうでしょうか:

init.sql
CREATE DATABASE IF NOT EXISTS Products;

# create tables here
# add seed data inserts here

今回、多くを持っていませんが、絶対拡張できることが分かると思います。それが重要です。

サマリー

このシリーズについて一周まわって、最初からすべてを説明しました。基本的な概念、主要コマンド、Volume とデータベースの扱い方、そして、Docker Compose のより効果的に使う方法などです。このシリーズは今後も継続して Docker の世界へ深く深く進んでいきますが、少しでもお役に立てれば幸いです。ここまで読んでくれてありがとうございました。

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

Dockerfileで 環境構築を自動化

はじめに

本記事は動画( https://youtu.be/RYXtItghA14 )で説明に使用している
スライドを記事化したものです。動画と合わせて御覧ください。
RYXtItghA14

※記事化する際に補足説明を加筆しており、内容は動画のスライドと異なります。
※本記事の内容は2020年3月時点の内容となります。OSやミドルウェア、Dockerのバージョンが異なることで記載通りの内容で完了しない場合があります。


Dockerfileで出来る事

  1. イメージのダウンロード
  2. コンテナイメージ内でのシェルコマンド実行
  3. ローカルファイルをコンテナイメージ内への転送
  4. 実行ユーザ切り替え

Dockerfileで出来ない事

  1. デーモン(サービス)の起動
  2. 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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.php
    protected function driver()
    {
        $options = (new ChromeOptions)->addArguments([
            '--disable-gpu',
            '--headless',
            '--no-sandbox', //追記
        ]);

        return RemoteWebDriver::create(
            'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }

よし、これで動いた!

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

docker 削除系

dockerのイメージ、コンテナ、ボリューム、ネットワークを全て消す

docker-compose down --rmi all --volumes

--rmiオプション

削除するイメージの種類を指定
allはすべてのイメージ
省略すると、イメージは消されない

--volumesオプション

docker-compose.ymlのvolumesの名前付きボリュームとコンテナにアタッチされたanonymous volumeが削除

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