イマドキの「Docker力」を身につけるPLAID式チュートリアル

こんにちは。
最近、肩書がTech Leadになりました。@otolabです。

さて、

イマドキのWebエンジニアとして、そこそこ幸せに生きるには、プログラミングの技量の他にも、前提となる様々な力が求められています。

或る人曰く、Shell力、Git力、そしてDocker力。

ーー そう、それは環境を操る力 ーー。

すみません、勝手に言っているだけです。

流石にそろそろDockerに手を出してみたいけどよくわからん。という人はまだ多いかと思います。手を出しかねる理由としては、

  • ほんとに役に立つのか
  • 覚えること多くてめんどくさそう
  • 記事によって書いてあること違わない?

だいたいこんな感じではないでしょうか。

つまるところ、取っ掛かりの教材となるものがあんまりないのかなー、なんて思います。新しもの好きが多いPLAID社内もあまり例外ではなく、開発環境のDocker化を目論む秘密結社がちょっと存在する程度に留まっていました。

しかし、最近になって本格的に開発環境をDockerに移行しようという機運が高まりまして、実践的にDockerを理解するためのHands-onおよびそのメソッドを教材化しておこう。という話になりました(という話にしました)。

今回はそんなPLAID式チュートリアル(ver-201807)を紹介させていただきます。

この記事が提供するもの

この記事は「イマドキのDocker力」を0から身につけるための一連のチュートリアルを提供します。

前提とする知識レベルは「通常のLinuxシステムについて基本的なことを理解しており、SSHによってHTTPサーバの簡易なメンテナンスができる程度」と置いています。わりと高めですのでご注意ください。

また、記事と同様の内容でHands-onのための教材一式を提供します。社内勉強会用に作ったもので、今後は開発のインストラクションの教材にする予定です。githubに公開リポジトリとしてまとめてありますのでcloneしてご活用ください。forkしたりIssueでのリクエストも歓迎しております。

かなり入門向けの内容なので多くの「?」は残ると思います。それらは別途調べてもいいですし、疑問の多くは使っているうちに徐々に理解できると考えています。(もしこの記事が好評なら続きを書くかもしれません)

コンテナ技術・オーケストレーション技術の、より深い発展形アイデアであるMetaparticleについては、前回弊社CTOが書いた記事がありますので、ぜひ読んでみてください。Dockerについての記事は他に、Moby ProjectLinuxKitを紹介した記事や、SmartHRさんとの合同勉強会を紹介した記事があります。

まずは疑念の解消から

  • ほんとに役に立つのか
  • 覚えること多くてめんどくさそう
  • 記事によって書いてあること違わない?
  • 理想形ってどんなもの?

ほんとに役に立つのか

あなたの作っているシステムはもしかしたら、Macなどのローカル環境での開発とLinux上へのデプロイを前提に、様々な支援ツールや設定ファイル、ドキュメント・ノウハウ集、デプロイ機構が既に組まれているかもしれません。

その場合、すぐには利便性を感じられない可能性は高いです。Docker化がもたらす大きな利便性は、それらをシンプルに一本化できるという点に他ならないからです。

ただ、Docker力がもたらす利便性はそこに留まりません。

ちょっとしたWebサーバを立てたり、使ったことのないミドルウェアを試用したり、構築が面倒なOSSのプロダクトを社内用に準備したり。……ところで、なんでMacにMongoDBNodeをインストールするんでしたっけ?そういえば、ローカル開発環境と本番環境でサーバの構成やライブラリは一致していましたっけ?CIってどうやってたっけ?

Docker力がついてくると、だんだんそのあたりが気になってくると思います。そうしたら、ようやく、あなたのシステムをDocker化するタイミングです。

ようこそ。

覚えること多くてめんどくさそう

一見多いですが、理解すればべつに難しいことはありません。

SSHで遠隔のサーバを叩くのとそんなに違いがないからです。Infrastructure as Codeについて知識があればより理解は早いでしょう。そして、それがもっと簡単に制御できるとしたら?

真にややこしい部分はリファレンスを見ながら一回やれば良いものが多いです。あるいはコピペで足りることも多い。

必要なのは記憶力ではなく頭の体操です。楽しいですよー。

記事によって書いてあること違わない?

はい。書いてあることが記事によって違うと思います。少なくとも数年内の記事だとコマンドのレベルで内容がだいぶ変わりました。内部で行われていることは変わらないのですが、コマンドがかなり簡単になっています。

このあたりはDocker Composeという簡易なオーケストレーション機能がDockerに内蔵されたことによります。Dockerの本質や構造について理解することは重要ですが、より簡単に使うためのツールとしていろいろな機能が提供されるようになっていますので、便利に使いましょう。

そのため、この記事のタイトルにも「イマドキの」という単語がついているわけです。

(※追記7/27:と言いつつ、はてブのコメントでdockerのコマンド体系が古いとご指摘いただきました。ありがとうございます。古いほうがコマンドが短くて楽という側面はあるものの、そのうち使えなくなる可能性もあるので、書き換えを検討しております。ひとまずは対応表をご参照ください)

理想形ってどんなもの?

まず、コードがデプロイされる開発環境・CI環境・ステージング環境・本番環境が統一されています。OSの種類・ライブラリ・ミドルウェアの構成が記述的に構築されており、完全に同一です。どこかのステージだけ環境依存の問題が発生する……というような厄介な問題が起きません。

各ステージ(開発・本番など)の違いは、オーケストレーションの層で表現されています。設定ファイルの管理・サーバ(コンテナ)の構成・システムのバージョン管理・死活監視・ロギング・権限の管理などがこの層で提供されているため、コード+実行環境を同一に保ったまま、システム全体としての振る舞いや特性だけを制御できます。

オーケストレーションを提供する層が追加されるため、コードをマイクロサービスの思想で書きやすくなります。複雑なサービス間の連携や、運用のための基本機能(ログや死活監視など)をオーケストレーションの層に逃がすことができ、サービス単体の構造をシンプルにできます。実体としてのサーバ群はリソースとして抽象化されるので、その上に好きなように構成をレイアウトできます。

オーケストレーションの層も含め、記述的に管理できることも重要です。単純にInfrastructure as Codeという意味でもそうですし、記述的だからこそ共有できるという側面も重要です。Docker Hubには公式・非公式を問わず構築済みのDocker Imageが公開されています(本チュートリアルではnginxのイメージを扱います)。また、例えばMongoDBのレプリケーション設定を含む環境構築のノウハウが記事として公開されています。

今回は本格的なオーケストレーションにまでは踏み込みませんが、Docker Composeという開発環境などに向いたシンプルな構成管理の機構を利用しています。

イマドキのDocker力を身につけるPLAID式チュートリアル

疑念が晴れたところで(?)。いよいよスタートです。

このチュートリアルはstep0からstep3までに分かれています。study1とstudy2の座学を含みます。

  • step0: 事前準備
  • study1: すこしだけ用語解説
  • step1: 環境の中を動き回る
  • study2: 登場人物を把握する
  • step2: Imageを作る
  • step3: 揮発性を理解する

Hands-on教材の中に雛形のファイルが用意してありますので、そちらをCloneすることでスムーズに進められると思います。(step0で準備します)

手順をたどって解説する部分と、理解のためのクイズとしてTRYするべき部分がありますので、ゆっくり取り組んでみてください。

各stepのTRY課題まで全てなぞった場合、想定時間は2時間〜3時間程度です。

step0: 事前準備

Docker for Macのインストール

こちらのページからダウンロード出来ます。ダウンロードの前にアカウントの作成とログインが必要です。めんどくさいですが、しょうがないので登録をお願いします。

ログイン後インストールの説明ページの中程から、stableとedgeという2つのバージョンを選択してダウンロードすることができます。現在、stableのバージョンがかなり遅れをとっており、速度面からedgeを使うことはほぼmustの状況にあります。(※追記7/27:記事を書いている間にstableが更新されたのでどちらでも大丈夫になりました)

また、Kubernatesのサポートも重要になってきているので、ぜひedgeを導入しましょう。不安定な時期もありましたが現在はほぼ安定しています。

この記事ではDocker for Macを前提にしますが、扱い方についてはDocker for Windowsでもほぼ同様です。

Kitematicの導入

Docker環境のGUI操作ツールです。たぶん読みはカイトマティック。

稼働中のコンテナや設定の状態などを簡単に確認できます。意外と使いやすい。

Docker for Macのメニューからダウンロードページに飛べるようなのですが、下記からダウンロードしたほうが簡単かもしれません。

https://github.com/docker/kitematic/releases/

ZIPをダウンロードして開き、Applicationsフォルダにコピーしてください。

gitの導入

ここまで読んできた人の環境には既にインストール済みではないか……と思いますので、割愛します。

Hands-on資料の取得

こちらのリポジトリをcloneしてください。

$ git clone https://github.com/otolab/plaid-study-20180605.git

この記事ではstep1, step2, step3のディレクトリを使います。

発表用のスライド資料についてはREADME.mdを参照のこと。
github pagesからもアクセスできます。

study1: すこしだけ用語解説

キーワード: Docker, コンテナ仮想化, Docker for Mac, Docker Cloud, オーケストレーション, Kubernates

Dockerとは、LinuxのContainerサポート機能であるLXCを利用したコンテナ実行環境です。

コンテナ仮想化とは、仮想マシンを実現する技術の一種です。一つのOSのコアで、独立した複数の仮想環境を提供する点に特徴があります。リソースの消費が少なくてすみ、比較的高速である点が利点として挙げられます。

Docker for Macとは、Mac OS上でDockerを使うためのツールのセットです。Mac上でLinuxの仮想マシンを立ち上げ、その中にDockerのコンテナを作ることでその機能を実現しています。

Docker Cloudとは、Dockerの開発元であるDocker社が立ち上げている一連のクラウドサービスです。特に重要なのはDocker Imageを作成・配布するDocker Hubです。

オーケストレーションとは、多数の要素から構成されるシステム全体の管理を指す言葉で、ここでは実サーバとその上で動くコンテナを管理し協調動作させるための仕組みを指します。中規模〜大規模なシステムの実現には欠かせない技術です。

Kubernatesとは、Googleが提供しているオーケストレーションプラットフォームです。Docker社が提供しようとしていたDocker Swarmを退け実質的な業界標準となりました。

step1: 環境の中を動き回る

$ cd ./step1

テーマ: 遊び方を覚える。

Docker Compose

  • $ cat docker-compose.yml
    • docker-compose.ymlはdocker-composeコマンドが参照するファイルで、仮想マシン(以下コンテナ)の定義が記述されています
  • $ docker-compose up -d
    • docker-compose.ymlに書かれたコンテナを立ち上げます
  • $ docker ps
    • 起動中のdockerコンテナの一覧を表示します
  • kitematicを実行して現在の状態を確認してみてください

コンテナの中に入ってみる

  • $ docker-compose exec container1 /bin/bash
    • コンテナの中でシェルを起動し、ターミナルとつなぎます
    • $ echo 'ok' > testfile
    • $ cat testfile
    • $ ls testfile
    • そのほかいろいろやってみてください
    • $ exit でbashを終了してコンテナから抜けられます

コンテナを止めてみる

  • $ docker-compose down
    • docker-compose.ymlに記述されたコンテナを停止します
  • $ docker ps
  • kitematicを実行して現在の状態を確認してみてください。
  • $ docker-compose exec container1 /bin/bash
    • エラーが出ます。コンテナが起動していないので動かせません

コンテナを停止するとまっさらの状態に戻る

  • $ docker-compose up -d
  • $ docker-compose exec container1 /bin/bash
    • $ cat testfile
    • $ ls testfile
      • 先程書き込んだファイルですが存在しません
      • 同じImageを使った別のコンテナなので、まっさらの状態に戻っています
    • $ exit で終了します

mongoのコンテナを足してみる

  • $ docker-compose down
  • docker-compose.ymlのコメントを外す
  • $ docker-compose up -d
  • $ docker-compose logs mongo

mongoに触ってみる

  • $ docker-compose exec container1 /bin/bash
    • $ apt-get update && apt-get install mongodb-clients
    • $ mongo mongo:27017
    • $ exit で終了します

TRY

  • mongoのバージョンアップをしてみる
  • $ docker-compose exec container1 mongo mongo:27017 は何が起きる?
  • 止めたらどうなる?
    • apt-getしたmongodb-clientsもmongodbの中身も消える
    • 消えるというより、まっさらな状態に戻る(データの寿命についてはstep3で)

study2: 登場人物を把握する

ここまでと、ここからのために。やるきのない絵のスライドを見つつ。座学パートです。

キーワード: Image, Container, Process, Volume, Port

slide_07-1

Image

コンテナがマウントするファイルシステムや、起動時の設定をまとめたパッケージ

  • $ docker images
    • いままで使用してきたImageが一覧される
    • docker-composeがDocker Hubからダウンロードしたものや、自動ビルドしたものが含まれています

slide_02

Container

仮想マシンインスタンス

  • 重要なポイント
    • ContainerはImageを書き換えません
    • 一つのImageから同時に複数の、独立したContainerを作ることができます
  • $ docker ps
  • $ docker ps -a
    • -a停止状態 のコンテナも表示します
    • 停止状態は、コンテナは存在するがルートプロセスが止まっている状態です(後述)
  • docker-compose downするとコンテナは削除されます。これはコンテナが 存在しない状態 です

slide_03

Process

ルートプロセスはコンテナの作成時にEntrypointとして起動されたプロセス

  • 通常の独立したLinuxシステムでは、伝統的に/bin/initが起動時に実行されますが、Dockerコンテナではもっとシンプルな初期起動スクリプトを都度書くことが慣習です
  • $ docker-compose logs -f
    • ルートプロセスの標準出力・標準エラー出力が集約されて表示されます

slide_04

Volume

コンテナの寿命とは独立して管理されるデータ

  • $ docker volume ls
    • 一覧を表示します
  • Host Volumeはホスト側のディレクトリツリーをVolumeとしてコンテナにマウントすること(後述)

slide_05

Port

外部システムと通信するためのポートバインド

  • kitematicでmongoのコンテナを見てみましょう
  • Docker for Macではlocalhost:xxxxとして、内部のコンテナのポートをバインドし、アクセス可能な状態にすることができます

slide_10

step2: 環境を作る

$ cd ../step2

テーマ: Docker Imageを作ってみる。

Dockerfile

  • $ cat Dockerfile
    • Docker Imageを構築する手順が記述されています
    • Infrastructure as Codeの観点でみると理解しやすいでしょう
  • 実はDockerfileを使わずにImageを作ることも出来ますが、Image作成を試行錯誤する場合以外で行うことはほぼありません

挙動を把握する

  • $ cat entrypoint.sh
    • 1秒ごとに標準出力にメッセージを表示します
    • 表示メッセージは環境変数、テキストファイルの中身の2つから構成されます
    • テキストファイルがなくなった時、ループが終了します
    • 開始時にファイルが存在しない場合、空のファイルをつくります(touch

作ってみる

  • $ docker-compose build

起動してログを見る

  • $ docker-compose up -d
  • $ docker-compose logs -f
  • kitematicで開いてみてみましょう

入ってみる

  • $ docker-compose exec container2 /bin/bash
    • $ vi message.txt
      • kitematicでみると出力内容が変わるのがわかると思います
    • $ rm message.txt
      • 止まります
      • コンテナはあるけどルートプロセスがいない停止状態

TRY

  • kitematicから停止状態のコンテナをstartしてみる
  • docker-compose.ymlから環境変数上書きしてみる
  • mongodb-clientsとjqをDockerfileで入れて、mongoコンテナとつないでみる(Mongoに慣れてるならばTRY)

step3: 揮発性を理解する

$ cd ../step3

テーマ: 公式Imageで遊び、データの寿命を理解する。

公式nginxをカスタマイズしたImageを作る

  • $ cat Dockerfile
  • $ docker-compose build
  • $ docker-compose up -d
  • ブラウザでlocalhost:81にアクセスしてみる
    • 適宜リロードして状態が変わるのを確認してください

Volumeの設定を確認する

  • $ cat docker-compose.yml

一時的な編集

  • $ docker-compose exec container3 /bin/bash
    • $ vi index.html
    • 適当に編集する
    • $ exit で終了します
  • $ docker-compose down
    • Containerを消す
  • $ docker-compose up -d
    • 編集が消えている

Volume

  • $ docker-compose exec container3 /bin/bash
    • $ vi volume/index.html
    • $ exit で終了する
  • $ docker-compose down
    • Containerを消す
  • $ docker-compose up -d
    • 編集は消えていない
  • $ docker-compose down -v
    • Containerを消し、Volumeも消す
  • $ docker-compose up -d
    • 編集が消えている

Host Volume

  • $ docker-compose up -d
  • $ vi ./host-volume/index.html
    • ホスト側(Mac上)で編集する
  • 内部的にはosxfsというネットワークファイルシステム的なものが動いている

TRY

  • ポートをlocalhost:83に変えてみる
  • $ docker-compose kill
    • docker-compose downの代わりにkillを実行した場合の挙動を見てみる
  • SSL自己証明書込みのnginx Imageを作ってみる
    • やり方は検索する
    • すでに非公式Imageがある……かも?

結び

お疲れ様でした。

どうでしょう?Docker力、身についた感じはしますか?

ここまで把握しておけば、いろいろ遊べる準備が整ったんじゃないかと思います。下記の基礎知識を得られていれば大成功です。

  • Docker Composeによる環境の作成と基本的な操作
  • DockerfileによるカスタマイズしたImageの作成
  • データの寿命についての感覚

内部の仕組みについても「?」がたくさんあると思いますし、使っていてもいろいろと謎な部分が出てくると思いますが、ここから先はごりごり進んでいけるんじゃないかと思います。

詳しい方は「えー、そこなの?」とツッコミを入れながら読んだかも知れないですね。このメソッドでは「日頃使う部分を体感する」ことを重視したので、解説は少なく・詰め込み気味の構成になっていると思います。揮発性については引っかかる人が多いので厚めになっています。

あくまでver-201807と考えているので、社内で使いながら随時アップデートしていく予定です。より良い内容になればと思っておりますので、ご意見頂けると幸いです。

さて。

ちょっとした意見だけじゃものたりない、もっとこうしたらいい!と熱い想いを抱えたあなた。やるきのなさすぎる挿絵を描き直したい!と思ったあなた。そう、そこのあなたです。CXプラットフォーム「KARTE」を運営するプレイドでは、 KARTEを支える技術に興味を持つエンジニア(インターンも!)を募集しています。詳しくはこちら(Wantedly)をご覧ください。