ブログ

ryuzeeによるブログ記事。不定期更新

直近開催のScrum Alliance認定スクラムマスター研修のご案内

5分で分かるDockerのキホン

全国100万人のImmutable Infrastructure職人のみなさんこんにちは。 もう誰も彼もがDockerなので、あんまりブログに書こうという気にもならなかったのですが、知り合いからリクエストを貰ったので、5分くらいで分かるようにかいつまんで概略を説明します。

Dockerとは

  • 詳しくは本家サイト見ればだいたい分かる。
  • 仮想化技術
  • コンテナ単位でパッケージング
    • VirtualBoxとかと違って高速、オーバーヘッドが少ない。chrootに近い。LXCには依存しなくなっている
    • コンテナごとにIDが振られる
    • コンテナは差分保存なのでロールバックも簡単
  • 一回作ればどこでも動く。Javaっぽい
  • Dockerfileでコンテナを作成する
    • Dockerfileの1行ごとにコンテナIDがフラれる
  • 動作環境
    • Linux Kernel 3.8以降 64bit OS
    • Macの場合はVirtualBoxの中で動かす形になる→ boot2docker
    • Windowsの場合もVirtualBoxを使って仮想マシンの中にDocker環境を作ることになる。
  • 何がうれしいの?
    • 高速に起動する。したがってCI用に使ったり、Chefのクックブックの実験環境に使ったり、開発環境に使ったり色々便利。もう本番環境で使っている例も多数
    • コンテナ内に閉じ込めることでポータビリティがあがる。アプリケーションのデプロイ戦略が楽な方に大きく変わりうる
    • 差分で管理されるので配布と再利用が簡単
    • いろんな環境で動く
    • Dockerfileを使ってコードでインフラを管理できる

Ubuntu 12.04 LTS 64bitで動かす

まずKernelを3.8に変更する

sudo apt-get update
sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring
sudo reboot

aptレポジトリを追加してインストール

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo sh -c "echo deb https://get.docker.io/ubuntu docker main /etc/apt/sources.list.d/docker.list"
sudo apt-get update
sudo apt-get install lxc-docker

とりあえずDockerを使ってUbuntuのコンテナを起動する

sudo docker run -i -t ubuntu /bin/bash

初回なのでたくさんイメージをダウンロードするのでちょっと時間がかかるはず。終わると以下のようにログインできている

Unable to find image 'ubuntu' locally
Pulling repository ubuntu
316b678ddf48: Download complete 
a7cf8ae4e998: Download complete 
3db9c44f4520: Download complete 
()
cb12405ee8fa: Download complete 
4d26dd3ebc1c: Download complete 
d4010efcfd86: Download complete 
root@6485cdbce682:/# 

この状態だと、インタラクティブシェルで、exitするとプロセスが終了する。

どのコンテナが起動しているかを確認する

sudo docker ps

として確認すればOK。(ps -a だと停止済のコンテナも含む)

コンテナ自体を削除する場合

以下のようにする(末尾のパラメータはコンテナID)

sudo docker rm 04b26990125f

複数のコンテナをまとめて停止したり削除する

以下のように引数にコマンド実行の結果を渡せばOK。

sudo docker stop `sudo docker ps -aq`
sudo docker rm `sudo docker ps -aq`

独自のイメージを作る

適当に変更を加えたあとにログアウトし、

sudo docker commit コンテナID 適当な名前

のようにする。作ったものを確認するには

sudo docker images 名前

として一覧に出ることを確認すればOK

たとえば

sudo docker commit eb0dd1195df2 ryuzee/apache2

これができれば

sudo docker run -i -t ryuzee/apache2 /bin/bash

にように今度はこれを使うことができる。なお、イメージの名称は、ユーザー名/中身 という形式にするのが推奨

イメージの一覧を取得する

sudo docker images

とすることでイメージの一覧が取得できる。

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              13.10               5e019ab7bf6d        4 weeks ago         180 MB
ubuntu              saucy               5e019ab7bf6d        4 weeks ago         180 MB
ubuntu              12.04               74fe38d11401        4 weeks ago         209.6 MB
()
ubuntu              10.04               3db9c44f4520        4 weeks ago         183 MB
ubuntu              lucid               3db9c44f4520        4 weeks ago         183 MB

Dockerfileでイメージを作る

FROM ubuntu
RUN sudo apt-get update -y
RUN sudo apt-get install apache2 -y
RUN sudo apt-get install memcached -y
RUN sudo apt-get install php5 -y

## 環境変数の設定
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2

## 公開するポートの指定
EXPOSE 80

## コンテナ起動時に実行するコマンドを指定
CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]

のように、ベースとするイメージを指定したあと、実行するコマンドを書いていく。これができたら

sudo docker build .

を実行するとビルドされる。ただしこれで作られたイメージには名前がついていないので、

sudo docker build -t 名前 .

のようにすると良い。もしくはあとから名前をつける場合は、

sudo docker tag bc9e46f7accc ryuzee/apache2

のようにする

Dockerfile内で使えるコマンド

FROM <image> 元となるイメージを指定する。:の後ろでタグ指定可能
MAINTAINER <name> メンテナの名前
RUN <command> ビルド中に実行したいコマンドを指定。パッケージのインストールとか設定とか
CMD <command> 起動後のコンテナで実行したいコマンドを指定する。1つしか書けない
EXPOSE <port> [</port><port> ...] 外部に公開するポートを指定
ENV <key> <value> 環境変数の設定
ADD <src> <dest> ファイルを配置。絶対パスで記述する

Dockerfile作成上の注意

  • ENTRYPOINTやCMDは1つのDockerfileの中で1個しか指定できない
  • したがって複数プロセスを起動したい時はsupervisordを使って行う

イメージの削除

以下のように引数にイメージIDを指定する。ただし依存するコンテナが存在する場合は削除できない

sudo docker rmi f6eb3276aab2

ポートの設定

Dockerfileの中でEXPOSEを使って指定するか、起動時に設定する。以下の例では、コンテナ側の80番にポートフォワードするために母艦側で8888を指定している

sudo docker run -d -p 8888:80 ryuzee/apache2

起動サービスの設定

Dockerfileの中でCMDを使って指定するか、起動時に設定する

docker run -d -p 8080:80 ryuzee/apache2 /usr/sbin/apache2 -DFOREGROUND

ローカル側のディスクを共有

あらかじめDockerfileの中で公開するVOLUMEの設定をしておいた上で、起動時に -v を使ってローカル側:コンテナ側の形で指定する。なお、絶対パスで指定する必要がある点には注意。

ログ系とかは外だしにしとくと便利かも。

sudo docker run -p 9999:80 -p 2222:22 -t -v /home/ryuzee/docker/basic/logs:/var/log/apache2 -d ryuzee/basic

イメージの共有

Docker Registryを使って作成したイメージを共有することができる。例えば、パブリックレジストリを使うと世の中に公開したり、他の人が公開しているものを使ったりできる

公式レポジトリとコマンドラインをひもづけるには

sudo docker login

としてログインすればOK

作ったイメージを公開するには、

sudo docker push ryuzee/basic

としてプッシュしてあげれば良い。

以下のようなログが表示される。

The push refers to a repository [ryuzee/basic] (len: 1)
Sending image list
Pushing repository ryuzee/basic (1 tags)
511136ea3c5a: Image already pushed, skipping 
Image f10ebce2c0e1 already pushed, skipping
Image 82cdea7ab5b5 already pushed, skipping
Image 5dbd9cb5a02f already pushed, skipping
Image 74fe38d11401 already pushed, skipping
869d76ced5c7: Image successfully pushed 
(略)
424924b964f9: Image successfully pushed 
4f0307fd0f8f: Image successfully pushed 
d77d7fd91796: Image successfully pushed 
532d67a9eec2: Image successfully pushed 
5804bf0385b9: Image successfully pushed 
Pushing tag for rev [5804bf0385b9] on {https://registry-1.docker.io/v1/repositories/ryuzee/basic/tags/latest}

自分用のDocker registryをたてる

index.docker.io だけでなく、自分でDocker Registryを作ることができる。またこのとき、Amazon S3にファイルが保存できるので、AWS内に仮想マシンをたててDocker使う場合はネットワーク的なメリットもある。

手順

まずS3に適当にバケットを作成しておく。今回は東京リージョンにryuzee-dockerimageという名前で作成。 なお、docker pullして持ってくるregistryは古いので、できればGitHubから最新を持ってきたほうが困らない感じ。

git clone https://github.com/dotcloud/docker-registry
cd docker-registry
sudo docker build -t ryuzee/registry .

コンテナを起動する。-eで環境変数を指定しており、アプリの中で必要なAWSのアクセスキーやシークレットキーを指定している。もちろんコンテナの中にconfig.ymlを置いたり、起動時にVOLUMEを使って設定ファイルを外部から共有してもOK。

sudo docker run \
         -e SETTINGS_FLAVOR=s3 \
         -e AWS_BUCKET=ryuzee-dockerimage \
         -e STORAGE_PATH=/images \
         -e AWS_KEY=AKIXXXXXXXXXXXXXXXXXX \
         -e AWS_SECRET=abcnjsifhAHFkfkjidjdjdjdiki \
         -e SEARCH_BACKEND=sqlalchemy \
         -p 5000:5000 \
         ryuzee/registry

ここまでできたら、まず以下のようにタグをつけて

sudo docker tag bb34bb42eb3a localhost:5000/ryuzee/basic

その後にレポジトリにプッシュする

sudo docker push locahost:5000/ryuzee/basic

Pullしたいときの考えかたも基本的に一緒

sudo docker pull localhost:5000/ryuzee/basic

dockerコマンドでsudo毎回叩くとかありえない人向け

dockerグループに自分を追加してあげることでsudo付けなくてもOKになる。なお作業完了後、シェルの再起動が必要なので、ログアウト/ログインする

sudo groupadd docker
sudo gpasswd -a ryuzee docker
sudo service docker restart

Ubuntu上のVagrantから簡単に操作する

Vagrant 1.6系からDockerに正式対応したので、Ubuntu上だとかなり楽に使える。 Vagrantfileは以下のようになる。

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image = "ryuzee/basic"
  end
end

これを用意して、いつもどおり

vagrant up --provider=docker

とすればOK

vagrant sshでログインしてごにょごにょしたい場合は以下のようにhas_sshを有効にしつつ、sshでの接続ユーザー名やキーペア(またはパスワード)とポート番号を指定する(ポート番号を指定しない場合、なぜかBad Portというエラーになるので注意)

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image = "ryuzee/basic"
    d.remains_running = false
    d.has_ssh = true
  end
  config.ssh.username = "root"
  config.ssh.password = "root"
  config.ssh.port = "22"
end

さらにコンテナ起動時のCMDを指定したり、ポートマッピングを設定することも可能。

## このあたりが追加になる
d.cmd = ["/usr/sbin/httpd", "-DFOREGROUND"]
d.ports = ["8888:80"]

過去の資産の再利用

Chefとの組み合わせ方

packerを使ってイメージの作成を行えば、過去の資産の再利用が可能。Packerは0.6以上のバージョンにすること。 以下の例では、BerkshelfおよびChef-Soloプロビジョナーとの組み合わせで、Dockerのイメージを作成している。

{
  "builders": [{
    "type": "docker",
    "image": "centos",
    "export_path": "image.tar"
  }],
  "provisioners":[
  {
    "type": "chef-solo",
    "cookbook_paths": ["./vendor-cookbooks/"],
    "run_list": ["timezone", "apache2-simple", "memcached"],
    "json": {"memcached":{"maxcon":"512","cachesize":"512"}},
    "prevent_sudo": true,
    "skip_install": false
  }],
  "post-processors": [{
    "type": "docker-import",
    "repository": "ryuzee/packer-sample",
    "tag": "0.1"
  }]
}

ソースはこちら。 一点気をつける点としては、DockerfileでサポートされているEXPOSEやENDPOINTやCMDなどを現時点ではサポートしていないため、自分でdocker runの際に引数で渡す必要がある。

あとは頼んだ…

アジャイル開発チーム向けのコーチングや、技術顧問、Scrum Alliance認定スクラムマスター研修などのトレーニングを提供しています。お気軽にご相談ください(初回相談無料)
前の記事 Grafanaを使ってGraphiteのデータを表示するダッシュボードを作る
次の記事 Sensu on AWSな話

プロダクト開発で、こんな課題を感じていませんか?

  • 何を作るべきか、順位の決め方が定まらない
  • プロダクトの方向性をチームで共有できていない
  • 開発組織の体制や役割がうまく機能していない
  • 開発プロセスが形骸化し、目的を見失っている
  • アジャイルを導入したが、組織に定着しない

プロダクトマネジメント、組織構造、開発プロセスの課題について、組織全体の視点から支援します。

お問い合わせ(初回相談無料)

契約を前提にした相談でなくて構いません。相談に際して事前の整理や準備は不要です。

Aligned ―プロダクト開発におけるステークホルダーとの関係性の築き方
ダイナミックリチーミング 第2版
Tidy First?
脳に収まるコードの書き方
プロダクトマネージャーのしごと 第2版
エンジニアリングマネージャーのしごと
チームトポロジー
スクラム実践者が知るべき97のこと
プロダクトマネジメント
SCRUM BOOT CAMP THE BOOK
みんなでアジャイル
レガシーコードからの脱却
Effective DevOps
変革の軌跡
ジョイ・インク
アジャイルコーチの道具箱
カンバン仕事術
Software in 30 Days
How to Change the World