dockerイメージ構築 実践テクニック
TRANSCRIPT
Dockerイメージ構築 実践テクニック
Haruka Iwao Storage Solution Architect, Red Hat K.K.
February 12, 2015
自己紹介 • 岩尾 はるか (@Yuryu) • 所属: レッドハット株式会社
– ストレージソリューションアーキテクト – 大手家電メーカー、ソーシャルゲーム会社、
Web広告ベンチャーを経て現職 • 大学・大学院で高性能計算(HPC)、分散ファイルシステムを研究
• ゲーマーです(主に某国産MMORPG)
Dockerイメージの構造
RHEL
nginx
Webサーバー
OSの基本ファイル
OSの基本ファイル
OSの基本ファイル
nginx
nginx HTMLファイル
追加
追加
nginxイメージを元に作成
RHELイメージを元に作成
実体は共有
新規
Dockerイメージの作成手順 • 2ステップで作成できます
• Dockerfile の作成 • $ docker build -t <tag> Dockerfileの場所
– 例) $ docker build -t yuryu/test .
Dockerfileとは • イメージ作成の手順を書いたもの • 例)
FROM registry.access.redhat.com/rhel RUN yum -‐y install httpd ADD index.html /var/www/html/index.html EXPOSE 80 CMD ["/usr/sbin/httpd", "-‐DFOREGROUND"]
Dockerfile 文法 • FROM - ベースとなるイメージ • RUN - イメージ構築で実行するコマンド • ADD - イメージ内にファイルを追加 • EXPOSE - ポートを外に見せる • CMD - デフォルトで実行されるコマンド
FROM registry.access.redhat.com/rhel RUN yum -‐y install httpd ADD index.html /var/www/html/index.html EXPOSE 80 CMD ["/usr/sbin/httpd", "-‐DFOREGROUND"]
Dockerfile 文法(2) • MAINTAINER - メンテナを書く • USER - コンテナ内で実行するユーザー • WORKDIR - 基準ディレクトリの変更 • COPY - ホストからファイルのコピー
– ADD が大きすぎるので分割 • その他リファレンスは下記
– https://docs.docker.com/reference/builder/
作って動かす • $ docker run で実行
– -d バックグラウンドで実行 – -P EXPOSE したポートを割り当て $ mkdir demo-‐apache $ cd demo-‐apache $ curl -‐L -‐o Dockerfile bit.ly/1FA902p $ echo “Hello, Docker!” > index.html $ build -‐t demo-‐apache . $ docker run -‐dP demo-‐apache
docker build 実行例 [yuryu@rhel7 docker-‐apache]$ docker build -‐t demo-‐apache . Sending build context to Docker daemon 3.584 kB Sending build context to Docker daemon Step 0 : FROM registry.access.redhat.com/rhel -‐-‐-‐> e1f5733f050b Step 1 : RUN yum -‐y install httpd -‐-‐-‐> Using cache -‐-‐-‐> 3679b20fa9ba Step 2 : ADD index.html /var/www/html/index.html -‐-‐-‐> Using cache -‐-‐-‐> db91c285d5ad Step 3 : EXPOSE 80 -‐-‐-‐> Using cache -‐-‐-‐> c9ceb17b169f Step 4 : CMD /usr/sbin/httpd -‐DFOREGROUND -‐-‐-‐> Using cache -‐-‐-‐> 4e99155706f6 Successfully built 4e99155706f6
docker run 実行例 • ランダムなポートと、コンテナID、コンテナ名が割り当てられる
[yuryu@rhel7 docker-‐apache]$ docker run -‐dP demo-‐apache 8d6b20a1e23427ad575bed1aee9cbea5406e5ed648a645e955cd6c6c6a34ea0a [yuryu@rhel7 docker-‐apache]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d6b20a1e234 demo-‐apache:latest "/usr/sbin/httpd -‐DF 4 seconds ago Up 4 seconds 0.0.0.0:49247-‐>80/tcp jovial_jones
いくつかの応用パターン • 固定ポートの割り当て • コンテナのリンク • コンテナ内のボリュームを共有 • コンテナ外とボリュームを共有
固定ポートの割り当て • $ docker run -p <host port>:<guest port> • $ docker port コマンドでもポートの割り当てを確認できる
[yuryu@rhel7 docker-‐apache]$ docker run -‐dp 80:80 demo-‐apache b027be3d09ace7c8cac594c14d07d3ddda5c32f15e14f8a28297714a69723c54 [yuryu@rhel7 docker-‐apache]$ docker port b027be3d09ac 80/tcp -‐> 0.0.0.0:80
コンテナのリンク • --link <コンテナ名>:alias • EXPOSEしたポートを環境変数に入れる # docker run -‐d -‐e MYSQL_ROOT_PASSWORD=root -‐-‐name mysql mysql # docker run -‐it -‐-‐link mysql:mysql mysql /bin/bash # env |grep MYSQL_PORT MYSQL_PORT_3306_TCP_PORT=3306 MYSQL_PORT_3306_TCP=tcp://172.17.0.155:3306 MYSQL_PORT_3306_TCP_PROTO=tcp MYSQL_PORT_3306_TCP_ADDR=172.17.0.155 MYSQL_PORT=tcp://172.17.0.155:3306 # mysql -‐-‐host=$MYSQL_PORT_3306_TCP_ADDR -‐-‐port=$MYSQL_PORT_3306_TCP_PORT -‐-‐password=root
ALIAS_PORT_XXX ALIAS_PORT_XXX_TCP ALIAS_PORT_XXX_TCP_PROTO ALIAS_PORT_XXX_TCP_ADDR ALIAS_PORT_XXX_TCP_PORT
コンテナのリンク(図)
提供コンテナ 使うコンテナ link
alias EXPOSE
環境変数
コンテナ内のボリューム共有 • 例: VOLUME /var/lib/mysql • --volumes-from <コンテナ名> で利用 • Data-only コンテナをベースに使うと良い
# docker run -‐d -‐-‐name mysql_volume mysql echo MySQL Volume Container # docker run -‐-‐volumes-‐from mysql_volume -‐d -‐e MYSQL_ROOT_PASSWORD=root -‐-‐name mysql mysql
Docker 1.4以降は docker run の代わりに docker create を利用する (ボリューム生成のタイミングが変更されている)
コンテナ外とのボリューム共有 • -v <host path>:<container path> • SELinuxの設定が必要
– # chcon -Rt svirt_sandbox_file_t
$ mkdir mysql-‐volume; cd mysql-‐volume $ sudo chcon -‐Rt svirt_sandbox_file_t . $ docker run -‐v $(pwd):/var/lib/mysql -‐-‐name mysql -‐e MYSQL_ROOT_PASSWORD=root -‐d mysql
Data-onlyコンテナのバックアップ
• ホストでボリュームを共有して、tarで固める
$ mkdir mysql-‐volume; cd mysql-‐volume $ sudo chcon -‐Rt svirt_sandbox_file_t . $ sudo docker run -‐-‐volumes-‐from mysql_volume -‐v $(pwd):/backup -‐-‐name mysql-‐backup fedora tar cfz /backup/mysql-‐backup.tar.gz /var/lib/mysql
$ sudo docker run -‐-‐volumes-‐from mysql_volume -‐v $(pwd):/backup -‐-‐name mysql-‐restore fedora tar xf /backup/mysql-‐backup.tar.gz -‐C /
ボリューム共有
Data only コンテナ 使うコンテナ
volumes-from
VOLUME
ホスト
-v <host>:<container>
Dockerで作るCI
開発者A
開発者B
コンテナの定義を共有
変更を通知
自動テストを実施
コンテナを取得して開発
開発者C
クラウドへデプロイを指示
GitHub
テスト済みコンテナイメージを クラウドサービスへデプロイ
コンテナイメージを作成
今回のデモの定義 • GitHubで公開中 • https://github.com/yuryu/docker-‐jenkins-‐demo
Red Hat Enterprise Linux
テスト ソースコードを取得
生成 起動
JenkinsのDockerfile FROM registry.access.redhat.com/rhel MAINTAINER Haruka Iwao RUN yum -‐y upgrade RUN curl -‐o /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-‐ci.org/redhat/jenkins.repo RUN rpm -‐-‐import https://jenkins-‐ci.org/redhat/jenkins-‐ci.org.key RUN yum -‐y install jenkins java git docker ADD run-‐jenkins.sh /root/run-‐jenkins.sh EXPOSE 8080 CMD /root/run-‐jenkins.sh
run-jenkins.sh #!/bin/sh JENKINS_HOME="/var/lib/jenkins" JENKINS_USER="jenkins" JENKINS_JAVA_OPTIONS="-‐Djava.awt.headless=true" JENKINS_PORT="8080" JENKINS_HANDLER_MAX="100" JENKINS_HANDLER_IDLE="20" JAVA_CMD="/usr/bin/java $JENKINS_JAVA_OPTIONS -‐DJENKINS_HOME=$JENKINS_HOME -‐jar /usr/lib/jenkins/jenkins.war" OPTIONS="-‐-‐httpPort=$JENKINS_PORT -‐-‐handlerCountMax=$JENKINS_HANDLER_MAX -‐-‐handlerCountMaxIdle=$JENKINS_HANDLER_IDLE " cd "$JENKINS_HOME" exec runuser -‐u $JENKINS_USER -‐-‐ $JAVA_CMD $OPTIONS
SlaveのDockerfile FROM registry.access.redhat.com/rhel MAINTAINER Haruka Iwao RUN yum -‐y upgrade RUN yum -‐y swap -‐-‐ remove fakesystemd -‐-‐ install systemd systemd-‐libs RUN yum -‐y install openssh-‐server java-‐1.7.0-‐openjdk RUN adduser jenkins RUN echo "jenkins:jenkins" | chpasswd RUN ssh-‐keygen -‐f /etc/ssh/ssh_host_rsa_key -‐N '' -‐t rsa RUN ssh-‐keygen -‐f /etc/ssh/ssh_host_dsa_key -‐N '' -‐t dsa RUN ssh-‐keygen -‐f /etc/ssh/ssh_host_ecdsa_key -‐N '' -‐t ecdsa RUN yum -‐y install gcc gcc-‐c++ automake autoconf make git libtool EXPOSE 22 CMD ["/usr/sbin/sshd", "-‐D"]
Slaveを作るときの注意点 • RHEL標準のコンテナイメージには
systemdが入っていません • fakesystemdが入っている • systemdに依存するパッケージを入れる場合は、本物のsystemdに置き換える – yum -y swap -- remove fakesystemd -- install
systemd systemd-libs • systemdをinitとして実行する必要は無い
Jenkins Docker Plugin • JenkinsスレーブをDockerで実行 • テストごとにコンテナを生成、削除
DockerにTCPをlistenさせる • Jenkinsから制御するために必要 • /etc/sysconfig/dockerを書き換える • このままだと認証なしに誰でもアクセス可能になるので注意!
OPTIONS=-‐-‐selinux-‐enabled -‐H tcp://172.17.42.1:5555 -‐H fd://
Jenkins実行手順 • Data-onlyコンテナを起動してから、
Jenkins本体を起動する
$ docker run -‐d -‐v /var/lib/jenkins -‐-‐name jenkins-‐home yuryu/demo-‐jenkins echo Data-‐only container for jenkins $ docker run -‐-‐volumes-‐from jenkins-‐home -‐d -‐p 8080:8080 yuryu/demo-‐jenkins
Jenkins本体の設定 • Manage Jenkins > Configure System
Dockerの状態を確認 • Manage Jenkins > Docker
プロジェクトの設定
今回デモで使うプロジェクト • 簡単なautoconf / gtest を使うCのプロジェクトを用意しました
• https://github.com/yuryu/gtest-‐demo
テスト実行中の様子 • コンテナ内で configure が走っている
テスト終了後 • 設定すれば、コンテナをイメージに
commitできる
実際にやってみます
cAdvisor • Dockerのための監視ツール
– https://github.com/google/cadvisor
cAdvisorの画面
cAdvisor起動方法 # setenforce Permissive $ docker run \ -‐-‐volume=/:/rootfs:ro \ -‐-‐volume=/var/run:/var/run:rw \ -‐-‐volume=/sys:/sys:ro \ -‐-‐volume=/var/lib/docker/:/var/lib/docker:ro \ -‐-‐publish=8080:8080 \ -‐-‐detach=true \ -‐-‐name=cadvisor \ -‐-‐volume=/cgroup:/cgroup \ google/cadvisor:latest
ご清聴ありがとうございました