Posted at

実例で学ぶDockerハンズオン

More than 3 years have passed since last update.

この記事はCAMPHOR- Advent Calender 2015 22日目の記事です。

こんにちはkohey18です!(`・ω・´)ゞ

学生時代はCAMPHOR-の4期代表として頑張ってから上京して今に至ります(`・ω・´)ゞ

この一年、インフラエンジニアとして業務でDockerを触る機会がたくさんあり、その中でインフラエンジニアだけでなく、サーバサイドエンジニアもアプリのエンジニアももっとDockerを手元で触ってもらってDocker力があるとどんだけ楽だろうか。。。と思うことが多々あり、週末なり時間のあるときに試して欲しいDockerハンズオンをまとめておこうと思いました。

週末とかで試してみて、「あぁなるほど」と思って貰えればと思います。


対象者


  • Docker初心者よりちょい上(一応初心者もわかるようにDockerfileの書き方から書いています)


    • とりあえずDockerをローカルに入れているけど、何もしていない

    • なんとなくDockerfileの書き方はわかる




Dockerとは

ここでは省略させてください!

様々な記事が上がっているかと思います!

書籍でいうと以下が良かったかも!

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)


ハンズオンゴール

文字にすると


  • docker-machineのポート8080のnginxコンテナにリクエストが来る(pオプションの理解)

  • Sinatraのアプリケーションはnginxコンテナのproxy_pass経由でしかつながらない(linkオプションの理解)

  • nginx, Sinatraのアプリケーションコンテナのログが全てfluentdのコンテナに送られる(logDriverの理解)

  • fluentdのログは全てローカルPCに出力される(vオプションの理解)

とそれぞれ一応、Dockerの基本的〜応用的なことがローカルの環境で実現できるようにします。


環境

docker-machineの設定(ポートフォワーディング等)は今回は省かせてもらいます。


構築手順


sinatra


  • Sinatra


    • Dockerfile

    • app.rb




Dockerfile

FROM ruby:2.2

MAINTAINER kohey

ADD app.rb app.rb
RUN gem install sinatra

EXPOSE 4567
CMD ["ruby", "app.rb"]



Dockerfileの書き方

初学者のためにDockerファイルの説明をすると、

Sinatraを動かすためにはもちろんrubyがコンテナ内で動いている必要がある。

今回、このコンテナ内のrubyの環境構築を楽にするためにrubyの2.2が動いているイメージを基にして、そこに上書きするようにしてみた。

先頭のFROM ruby:2.2がそこを表している。



  • ADD



    • docker build時にcurrent directoryのファイルをコンテナにぶち込む作業を行う。




  • RUN



    • docker build時にコンテナに走らせたい処理を記載。




  • EXPOSE


    • コンテナとして空けておくポートを記載。




app.rb


require 'sinatra'

set :bind, '0.0.0.0'

get '/' do
"Hello World!"
end


こちらはHello World!を出力するだけ

では、このSinatraアプリケーションのコンテナを動かしてみましょう!


$ docker build -t <your_name>/sinatra .
$ docker run --name sinatra -d <your_name>/sinatra
$ docker ps

kohey% docker ps                                                                   

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
acfa7757f698 kohey/sinatra "ruby app.rb" 13 seconds ago Up 14 seconds 4567/tcp sinatra

これで問題ないです。

このSinatraのコンテナ、外からは見れない状態です。

docker-machine内部からはport4567が空いているだけ。

上図のようにdocker-machine上にただ動いているだけ。

外から見れるようにするには、pオプションを利用すればいいのですが、それはnginxのコンテナで試してみましょう!


nginx


  • nginx


    • Dockerfile


    • nginx.conf




Dockerfile

FROM ubuntu

MAINTAINER kohey
RUN apt-get update

RUN apt-get install -y nginx
# Remove the default Nginx configuration file
RUN rm -v /etc/nginx/nginx.conf
# Copy a configuration file from the current directory
ADD nginx.conf /etc/nginx/
# Expose ports
EXPOSE 80
# Set the default command to execute when creating a new container
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]



nginx.conf


worker_processes 5;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$upstream_cache_status"';

access_log /var/log/nginx/access.log main;
sendfile on;

keepalive_timeout 65;

server {
listen 80;
server_name localhost;

location / {
proxy_pass http://sinatra:4567; #Sinatraのアプリケーションにproxyする
}
}
}


動かしてみましょう!


$ docker build -t <your_name>/nginx .
$ docker run --name nginx -p 8080:80 --link sinatra:sinatra -d kohey/nginx
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ac12ce7600cc kohey/nginx "/usr/sbin/nginx -g '" 6 minutes ago Up 6 minutes 0.0.0.0:8080->80/tcp nginx
acfa7757f698 kohey/sinatra "ruby app.rb" 11 minutes ago Up 11 minutes 4567/tcp sinatra


pオプション

docker run -p docker-machineのポート番号:コンテナ内ポート番号

となる。

例えば、docker-machineのipが192.168.99.100だとしたら、

docker-machineのipの調べ方はコチラ

192.168.99.100:8080はport80にフォワードされるから、すなわち、docker-machine内のnginxにリクエストが飛ぶこととなる。

かなり使うオプションなので抑えておいて欲しいです。


linkオプション

linkオプションを用いることでコンテナ間通信を可能にします。

すると、以下のようなところまで実現できました。

すると、外からnginxを通りproxy_passでsinatraのアプリケーションが見えるかと思います。

再掲: docker-machineのipの調べ方はコチラ

ここまで完全に理解できれば、最低限のDockerfileの書き方と最低限のオプションは理解できたかと思います。


応用編

Docker1.8からFluentd Log Driverが追加されました。

ローカルで試せるので少し試してみましょう!


fluentdのコンテナを立ち上げる


  • fluentd


    • Dockerfile

    • td-agent.conf




Dockerfile

FROM ubuntu

MAINTAINER kohey

RUN apt-get update && apt-get install -y --force-yes libssl0.9.8 curl

RUN curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh && mkdir -p /var/log/td-agent

ENV GEM_HOME /opt/td-agent/embedded/lib/ruby/gems/2.1.0/
ENV GEM_PATH /opt/td-agent/embedded/lib/ruby/gems/2.1.0/
ENV PATH /opt/td-agent/embedded/bin/:$PATH
ADD ./config/td-agent.conf /etc/td-agent/td-agent.conf
RUN mkdir -p /var/log
EXPOSE 24224
CMD ["td-agent"]



  • td-agent.conf


td-agent.conf


<source>
@type forward
@id forward_input
port 8888
</source>

<match **.**>
type copy
<store>
type file
path /var/log/td-agent/docker
</store>
<store>
type stdout
</store>
</match>


ログの入力をポート8888でHTTP通信で行うようにする。

動かしてみましょう!


$ docker build -t kohey/td-agent .
$ docker run --name td-agent -v /Users/kohey/Desktop/log/:/var/log/td-agent/docker -p 8888:8888 kohey/td-agent


vオプション

vオプションを使うとホストの任意のパスをコンテナの任意のパスにマウントすることができる

-v /Users/kohey/Desktop/log/:/var/log/td-agent

-v ホストの任意のパス:コンテナの任意のパス

こんな感じで書く

※※ 今回はdocker-machineが動いているVirtualBoxとローカルPCの共有フォルダを設定しているので、コンテナ -> VirtualBox -> ローカルMacPCが実現可能である。

ここまで来ました!!!

気がつけば大作になったぞ!!!


logDriverを使う

では、先ほど動かしたSinatraアプリケーションコンテナとnginxコンテナをstopしましょう。


$ docker rm -f sinatra
$ docker rm -f nginx

そして、再度、ログドライバーオプションをつけたSinatraアプリケーションコンテナとnginxコンテナを動かしてみましょう!


$ docker run --name sinatra -d --log-driver=fluentd --log-opt=fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}} kohey/sinatra
$ docker run --name nginx -p 8080:80 --link sinatra:sinatra --log-driver=fluentd --log-opt fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}} kohey/nginx

--log-driver=fluentd --log-opt=fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}}


  • log-driver


    • コンテナのログドライバーをfluentdにする(他のサポートもある)



  • log-opt


    • ログドライバーに必要な情報を与える



これでここまで来たかと思います!

ローカルのPCにログが出力されているはずなので見てみましょう!

下はローカルのPCに吐き出されたログをひたすらtailしている感じです!

fluentdのログもdocker.{{.Name}}より、docker.sinatraとかdocker.nginxとかになっていると思います!

これでハンズオンのゴールが出来たかと思います!


まとめ

最低限のオプション等々を紹介した感じの大作になってしまった。

僕は初めて触った時に

「linkオプションを利用しただけでhttp://sinatra:4567でproxy_pass通るのかよ!」

とか

「vオプションの使い方さえしっかりすればデータは永続化されそう!」

とか

「ログドライバーでコンテナのログが簡単に集まる・・・・!!便利じゃない??」

とかローカルの環境上でも感動する所は多々ありました。

実際、業務でもDocker使ってProduction運用していて、ログ周りとかデプロイ周りとか詰まりどころ多々あるけど、ちょっとずつ知見が溜まっている感じがします。

docker-machine上でちょっと凝ったことするときにこのハンズオンに出会ってもらえればなーとか思いました!

明日は、後輩のmikasakasaだよ!(`・ω・´)ゞ