Docker/Kubernetes 実践コンテナ開発入門
さて近年のエンジニアリングで外すことのできない重要要素、ITエンジニアが学んだ方が良いと上げられる技術要素で必ず出てくるDocker/Kubernetes周り。
僕も前から知ってはいたのですが仕事ではマシンやネットワークの制約からなかなか使えず、またなくても別に困っていないことからいまいち深掘りできていませんでした。Kubernetesについても恥ずかしながら「K8sを使うと何が嬉しいのか」というあたりがいまいち理解できていませんでした。
ということでコンテナについてもっと知っておこうと読んだのが本書。著者はサイバーエージェントでご活躍中の山田 明憲さん。(@stormcat24)。日本語で読めるコンテナ関連の本はかなり数も出ていますが、各所で高く評価された2018年刊行のDocker本の定番本です。
- Docker/Kubernetes 実践コンテナ開発入門
- 1.Dockerの基礎
- 2.Dockerコンテナのデプロイ
- 3.実用的なコンテナの構築とデプロイ
- 4.Swarmによる実践的なアプリケーション構築
- 5.Kubernetes入門
- 6.Kubernetesのデプロイ・クラスタ構築
- 7.Kubernetesの発展的な利用
- 8.コンテナの運用
- 9.より軽量なDockerイメージを作る
- 10.Dockerの様々な活用方法
- まとめ:Docker/Kubernetesの基礎から実践まで理解できる本
1.Dockerの基礎
1.1 Dockerとは
Dockerとはコンテナ型仮想技術を実現するための常駐アプリケーションdockeredとそれを操作するCLIからなるプロダクトである……と定義して、歴史や概念を含め、根本の部分を解説しています。
1.2 Dockerを利用する意義
- 実行環境が変わらないので冪等性を確保。
Immutable Infrastructure
- 実行環境の構築とアプリケーション構成の両方をコード化できる。
IaC: Infrastructure as Code
- 同じく、実行環境とアプリの両方が同じ箱に入るのでポータビリティが増す。(=どんなプラットフォームでも同じように動く)
- アプリケーションとミドルウェアの構成管理がしやすくなる
という話を核に、意義を説明しています。コンテナが複数ある時のアプリケーション管理をしやすくするツールとして Docker Compose
、さらにこのDockerが入ったサーバー(Dockerノード)が複数ある時にうまく管理できるコンテナオーケストレーションのツールとしてDocker Swarm
、さらにこのコンテナオーケストレーションの高機能なものとしてKubernetes
もここで登場します。
1.3 ローカルDocker環境を構築する
スクショも付随情報も豊富に解説されています。
前書きで作者さんが本書のテーマとして「コンテナで開発・運用していくための基本的な考え方を養えるようにする」を定義しています。それだけに様々な周辺情報もあり、元から日本語の本なので読みやすいです。
コラムも豊富でDockerの苦手分野、最初のころはLinuxコンテナを使っていた話、Docker for Windowsに苦戦したらDocker Toolboxがよい……などお役立ち情報も色々入っています。情報量が多いのはありがたいですね。
docs.docker.jp docs.docker.com
2.Dockerコンテナのデプロイ
2.1 コンテナでアプリケーションを実行する
- Dockerコンテナ用のファイルシステムや実行するアプリケーション、設定をまとめたテンプレートが「Dockerイメージ」。
- Dockerイメージを元に実体が生成され、ファイルシステムとアプリケーションが動いている状態が「Dockerコンテナ」。
と定義して、簡単な例で一連の流れをまずは解説しています。例に出てくるのがGo言語でHTTPサーバーになるコードで、さすがコンテナといえばGo-lang登場、尖ってるな!と思いました。
コード+設定を描いたDockerfileを入力に > docker image build
でDockerイメージが生成され、イメージ名を入力に > docker container run
でDockerコンテナが実行されるわけですね。
2.2 Dockerイメージの操作
各操作の説明。既存イメージの検索もコマンドからやるあたりはよく知りませんでした。
- 世の中の人がイメージを登録できる「Dockerレジストリ」があり、その代表が
Docker Hub
。 - GitHubへのpushと同じように
> docker image push
したり。 - Dockerレジストリからダウンロードしてイメージをビルドする際は
> docker image build -pull=true ...
。
2.3 Dockerコンテナの操作
今度はDockerコンテナの方の操作で、> docker container run
を始めとする各種コマンドが丁寧に解説されています。箱の外側からアクセスする際のポート番号と箱の中のポート番号の動きを対応させるポートフォワーディングも出てきます。
2.4 運用管理向けコマンド
ローカル上のディスクを消費していくイメージやコンテナを一括削除するのが > docker container prune
。フルーツのプルーン?と思ったら英語のpruneには「刈り取る」などの意味もあるのでした。
そして単独のコンテナならこれらのコマンド群で十分。しかしAPサーバーやDBなど複数のものからなるシステムを再現するため、複数のコンテナを扱うにはどうするのか...?ということで、docker-compose.yml
に設定を書いてから同じディレクトリで > docker-compose up-d
などして動かしていく Docker Compose
が登場します。
読んでいる時にちょうど触っていたJenkinsが例に出てきて分かりやすかったです。本格的にやる場合はJenkinsサーバーと違うマシン上に入れたりするSlaveの分も、Docker Composeを使えば一緒に制御できる訳ですね。
注釈も多く、コラムで操作対象を明確にするために長い方のdockerコマンドが今は推奨されている話もあったりして参考になります。
3.実用的なコンテナの構築とデプロイ
3.1 アプリケーションとコンテナの粒度
「Dockerの1コンテナ=マシン上の1プロセス」を厳密に守った方が良いのではと初期のDocker界隈では議論されていたが、現在ではこれは不適切。
「1コンテナ=1つの関心事(only one concern)
」、1つの役割や1つの問題領域猟奇に関わるが良いとのこと。Webサーバーのリバースプロキシで1つ、アプリで1つ、RDBで1つとか、Jenkins本体で1つでスレーブに1つづつということですね。
この関心事(concern)
という表現はクラス設計やアーキテクチャ設計の話でもよく出てきます。
3.2 コンテナのポータビリティ
どんなプラットフォームでも動くポータビリティがDockerの大きな長所だが、万能ではないよという話。
特にアプリにライブラリの実体を一緒に組み込むスタティックリンクでなく、実行する際にリンクするダイナミックリンクで問題が起きることがあるそうです。
3.3 Dockerフレンドリなアプリケーション
コンテナの外側からどう設定を渡すかの話。
- dockerコマンドの引数として渡す
- 設定ファイルとして渡す
- アプリケーションの挙動を環境変数で渡す ←オススメ
- 設定ファイルに環境変数を埋め込む。例えばJavaの
Spring Framework
はsome.hoge=${ENV_HOGE}
のように埋め込める
この中で環境変数で渡す方式を本書では推奨し、詳しく述べています。Kubernetes
やAmazon ECS
が例に挙げられていますが、AWSの他のサービスでもよく見るやり方なのでやっぱりそうなんだなあと。
3.4 永続化データをどう扱うか
例えばMySQLを実行するコンテナがあって、コンテナ再起動後も同じデータを使いたい時に場所を指定して実現するData Volume
の使い方。
3.5 コンテナ配置戦略
主にDockerホストが1つで複数のコンテナの時に使うcompose
、そしてDockerホストが複数の時に使うSwarm
の話。
Docker in Docker(dind)
といってDockerコンテナ自体をDockerホストにしてその中に入れ子が作れる- 複数のコンテナを集めた単位で制御できる Service という概念がある
- 複数のServiceを集めた単位でStackという概念がある。同じStack内のServiceはoverlayネットワークに属するので、コンテナ間通信が可能。
2018-2019年頃の進化で、Docker Swarm
を使うぐらいならもう上位互換のKubernetes
へ……と世の中的にはなっていきましたが、歴史を辿る上でも為になります。
4.Swarmによる実践的なアプリケーション構築
2018年頃の進化でオーケストレーションシステムの主流はKubernetesに変わったことを認めつつ、基礎技術を生かして手早い構築を一度学習するということでアプリケーションの構築です。フロントエンド入門の記事にもよく出てくるTODOアプリを作っていきます。
- DBはMySQLでmasterとslave
- APIサーバーとしてバックエンドはGo言語
- フロントエンドはVue.jsベースのNuxt.js
- そしてプロキシサーバーとしてnginxもフロント、バックエンドをそれぞれ別のService
として作っていきます。アーキテクチャ図と表があるのですが、frontendがあるのならapp*のところの名前にbackendを入れるとぱっと見もっと分かりやすいかな?とも思いました。
MySQL用のコンテナも同一シェルの中で環境変数で分岐してmasterとslave両方用意、docker container exec
コマンドの中にまたdocker container exec
の多段構成(!)……などなど高等テクニックがいろいろ。
コラムでやはり環境変数の活用が重要とあります。最終的にはlocalhostの上でWebアプリケーションとして動いてしまい、1つのマシン内でDockerコンテナを駆使するとこれができちゃうのか……!と感じました。
5.Kubernetes入門
5.1 Kubernetesとは
Docker Swarmを体感した後で、2017年秋にDockerがKubernetesを統合・サポートすることを発表してからメインとなったKubernetes
について。最初に歴史と位置づけが語られているのがありがたいです。
なお発音しにくい名前は本書では「クーベネティス」「クーベルネティス」「クバネテス」「ケーハチエス」「クベ」を上げています。
5.2 ローカル環境でKubernetesを実行する
Docker for Windows/Mac の管理画面からK8sをインストールし、コマンドラインツールのkubectlをインストール、kubectl
コマンドを使ってダッシュボードのインストール方法が解説されています。ctrl
ではなくてctl
ですね。
以前はこのローカル環境構築にはMinikube
が使われてきており、Windows10以外のWindowsでは今でもこの選択肢だそうです。
5.3 Kubernetesの概念
リソース
:K8sによるアプリケーションのデプロイを構成する部品のような構成要素で、これらが協調して動作していく。文脈によって語意がいろいろあるリソースとは意味が違う。
5.4 KubernetesクラスタとNode
5.5 Namespace
Namespace
:クラスタの中で入れ子で作れる仮想的なクラスタの概念。ふつうにクラスタを構築するとdefault, docker, kube-public, kube-systemの4つのNamespaceが用意される。
5.6 Pod
Pod
:1~N個のコンテナを中に持ったコンテナの集合体の単位。- 1つのPodは1つのNode(≒マシン)の中に配置される。レプリカとして複数のNodeの中に同じPodが配置されてもよい。1つのPodが複数のNodeをまたぐのはできない。
- Podをデプロイするときは設定をYAML形式のマニフェストファイルにその中のコンテナはこのimageだ...という設定を書き、
> kubectl apply -f simple-pod.yaml
のようにして実行。
5.7 ReplicaSet
ReplicaSet
:同一のPodを複数実行する時に使う概念。- Podと同じようにYAML形式の設定ファイルを書く。
kind: ReplicaSet
、replicas: {数}
となっている以外はPodリソースとだいたい同じ。同じくkubectlコマンドで実行。
5.8 Deployment
ReplicaSet
を管理・操作するための上位の概念。Deployment
がReplicaSet
を作り、ReplicaSet
がPod
群を作り……となる。- 同じようにYAML形式の設定ファイルで
kind: Deployment
として同じようなことを書いてkubectl
コマンドで実行。 - 配下の
Pod
数の設定を変えてもReplicaSet
は変わらず、コンテナの定義を変えるとPod
が止まって新しいものが生まれ、Deployment
のリビジョンも変わる。
5.9 Service
Service
:Pod
の集合に経路やサービスディスカバリを提供するための概念。ReplicaSet
の定義時に振り分けラベルのような設定を書いてkubectl apply
。その後ラベルがこの値のものだけ適用……のような設定を書いてkubectl apply
。するとその条件を満たすPod
にだけトラフィックが届く。- WebサービスのserviceやMircoservicesのserviceやレイヤードアーキテクチャのservice層などとはまったく意味が違う....
5.10 Ingress
Ingress
:Kubernetesクラスタの外へのService
の公開、HTTPルーティングを行うリソースの概念。使う時はやはり設定を書いてkubectl apply
する。HTTPで繋ぐWebアプリケーションのようなサービス公開時は必ず使う。
実際にDockerコマンドを打っての構築のイメージが湧いた後で見ていくと以前より理解しやすいです。改めてK8sは用語の概念が独特ですね……
6.Kubernetesのデプロイ・クラスタ構築
今度は本格的に、マネージドなK8sサービスではもっとも使われているというGCP
のGKE(Google Kubernetes Engine)
でK8sを使っていく章。
- ブラウザ上からプロジェクト作成。
- AWS CLIに相当する
Google Cloud SDK(gcloud)
を準備して、>gcloud container clusters ...
のコマンドで操作できる状態をセットアップ - ブラウザからK8sクラスタを新規作成
gcloud
からkubectl
に認証情報を渡し、以降は5章と同じように> kubectl apply -f filename.yml
で...
という感じで、4章でDocker Swarmを使って作ったTODOアプリ一式をGKEに上げていきます。設定ファイルの中身は色々書くものの、メインの操作はkubectl
コマンドで同じでした。詳細はなかなか難しいのですがイメージが湧きました。
最後にはオンプレ上でK8s環境を作る方法として、構成管理ツールのAnsible
を使ってK8sクラスタを一式作ってくれるツール、kubespary
の使い方も紹介されています。30分ぐらいで構築できるそうです。
7.Kubernetesの発展的な利用
K8sの応用編の章。
7.1 Kubernetesの様々なリソース
Job
: 1つ以上のPodを作成し、正常に完了するまでを管理してくれるリソース。Webアプリでなく計算やバッチのアプリ向け。実行は一度きり。CronJob
: scheduleキーでcron式を書くと、Jobを定期的に実行してくれるリソース。Secret
: 機密情報の文字列をBase64エンコードで暗号化したまま扱えるリソース。
7.2 ユーザー管理とRole-Based Access Control (RBAC)
- 認証ユーザー:Kubernetesクラスタ外から人間が操作するためのユーザーで認証方法が各種ある。複数ユーザがまとまってグループになる
ServiceAccount
:K8s内で管理され、Pod
がKubernetesのAPIを呼ぶときのユーザー。Role-Based Access Control(RBAC)
: 操作可能なAPIを定めたロールとユーザー・グループ・ServiceAccountを紐付て行うK8sの権限管理。
7.3 Helm
- 開発/本番/負荷テスト用など、環境が複数ある時はKubernetesクラスタも複数必要になる。これを解決する技術。
Chart
: 設定済みのK8sリソースのパッケージ。マニフェストファイルの原料が、Helmリポジトリに環境ごとに入っている。Helm
: このChartを管理するツール。インストールするとコマンドから> helm args...
で各種操作を行う。
7.4 Kubernetesにおけるデプロイ戦略
- Deploymentリソースのデフォルト設定が
RollingUpdate
。観測するとPodが1つづつ順番に入れ替わって新しいバージョンになる。 マニフェストファイルで数の細かい設定ができたり、ヘルスチェックができたりする。
オプション設定でなく
Deployment
リソースを2つ用意して行うのが、BlueGreen Deployment
。AWSなどでよく出てくるやつ。- 新しいバージョンのデプロイが終わったら、
Service
リソースのマニフェストファイルのラベルをコマンドで更新すると、ネットワークの流れる先が新しい方のDeployment
に切り替わる……というデプロイが実現できる。
巻末のコラムで複数サービスの基盤のレベルで各種課題を解決できるサービスメッシュの候補として、Linkered
とIstio
が紹介されています。本書の作者さんによると今後はIstioが最有力ということで、このへんの感触は書籍『マイクロサービスパターン』での記述と同じですね。
マイクロサービスパターン[実践的システムデザインのためのコード解説] impress top gearシリーズ
- 作者:Chris Richardson,長尾高弘,樽澤広亨
- 発売日: 2020/03/23
- メディア: Kindle版
8.コンテナの運用
コンテナを用いた開発を一通り見てきたので、今度はログ管理や障害対策といった運用の章。
- 普通のアプリでは物理ファイルにロギングするが、Dockerコンテナは異常終了してコンテナが物理的に削除されてしまうとログも消失してしまう。なのでコンテナ内では標準出力し、ホスト側で受け取ってログ出力する仕組みが一般的。
- Dockerには
logging driver
がデフォルトで入っており、JSONで出力したりAWS/GCP/Fluentdと連携できる。 - コンテナが多くなってきて大変になると、ログコレクタである
Fluentd
で収集、格納するデータストアにElasticsearch
、そして可視化ツールのKibana
で閲覧する方法が定番。 - Dockerホストが複数ある場合は各ホストに
fluentd
をエージェントとして配置する方法を推奨。 - Kubernetesの場合もだいたい同じ。すべてのNodeに必ず1つ配置されるPodを管理するリソース、
DaemonSet
という概念があるのでこれを使うと良い。 - その他のツールとして、AWS/GCP用のマネージドサービス
Google Stackdriver
がある。 - Kubernetesではログ閲覧をサポートするツール
stern
がある。
www.fluentd.org www.elastic.co www.elastic.co
- Dockerコンテナを動かすとdockerdというプロセスが常駐するが、これが停止してもコンテナを動かし続ける「ライブラリストア」という仕組みがある。
- Dockerの障害では動かすコンテナを間違えたりイメージを間違えて上書きしてしまったりがある。これを防ぐイメージのテストを行うツールとして
container-structure-test
というツールがある。 本番マシンのディスク容量の枯渇にも注意。
> docker system prune -a
で一括削除するとよい。Kubernetesには
Auto-Healing
という機能があり、NodeがダウンするとそこにあったPodの分だけ別の所で再配置してくれる。が、リソースが空いているNodeを自動で選んでいくため必ずしも望んだNodeに再配置してくれない場合もある。Pod再配置のルールをマニフェストファイルに定義できるPod AntiAffinity
という仕組みがある。- CPUリソースをたくさん消費する大食いなPodだけを専用Nodeに隔離する、
Node Affinity
という仕組みがある。 - Podのリソース使用率に応じてPod数を自動増減するKubernetesリソースが、
Horizonal Pod Autoscaler(HPA)
。 - Nodeの数を自動調整してくれるツールが、
Cluster Autoscaler
。
オートヒーリングというネーミングがHPが緑色まで自動回復しそうで楽しいです。(RPG脳) クラウドを学んでいると出てくるところですが、K8sにもいろいろな機能があるのだなあというところ。
9.より軽量なDockerイメージを作る
本書に出てきたサンプルを含めDockerイメージは普通に作ると数100MB~1GBぐらい。このイメージサイズが大きいとイメージのビルド、Docker Registryへの登録やダウンロード、実行、ディスク消費などなど諸々で積み重なって弊害が出てくるそうです。どれだけ軽量なコンテナを作れるのか……という実践的な追求をしていく章。
scratch
:Dockerが予約している特殊なイメージ。すべてのイメージの始祖。機能を削って極限までサイズを落としており、簡単なGo言語アプリを一緒にしたコンテナを作っても1-2MB程度。シェルも使えず、利用可能なユースケースはかなり限定的。BusyBox
:組み込み系でよく使われるLinuxディストリビューションでこちらは約1MB強。ユーティリティをハードリンクで組み込んでサイズを減らしている。最低限の機能はあるがパッケージマネージャーがない。Alpine Linux
:BusyBoxをベースにしたパワーユーザー向けディストリビューションで約4MB弱。パッケージマネージャーのapkが便利。これが使える。
scratchのことを「始祖」と表現していたのが面白かったのですが、極限までいくといろいろあるのですねえ。続いて、自分たちでDockerイメージを作る際の軽量化についてもテクニックを述べています。
- アプリのサイズ軽減:不要ファイルや外部ライブラリ軽減、画像サイズ軽減など。gitにコードがあるなら.dockerignoreファイルを置いて不要ファイルが入らないようにすると良い。
- Dockerイメージのレイヤー構造を意識する:Dockerfileに記述されたStepを1行づつ実行するごとに「レイヤー」が生成され、レイヤーの分だけtar.gzファイルができる。レイヤーの数を減らしたり、1行でまとめて実行するとその分減る。ただしやりすぎると分かりにくくなる。
multi-stage builds
:Docker17系より導入された仕組み。ビルドした成果物を置くコンテナと、デプロイして実行するコンテナを別にして軽くできる。DockerfileにFROMをビルド用コンテナと実行コンテナ用で2か所書く。有用。distroless
:Googleが公開しているOSを含まず言語にフォーカスした軽量イメージ。16MBぐらいでこちらも軽量。
本書はコマンド実行時のスクリーンショット類が豊富に掲載されていますが、それを踏まえると確かにレイヤー構造っぽい標準出力されてたな……!とイメージが湧きます。
またGo言語を語る際によく言語仕様の本体と基本ライブラリがコンパクトにまとまってコンテナ用途向け、などと語られますが、本章を読むとなるほどなあと分かります。同じイメージを元にしたコンテナが大量にデプロイされるような環境では、サイズの軽さが重要になる訳ですね。
10.Dockerの様々な活用方法
最後は応用的な使い方として、Dockerの活用法の章です。
- DB系とかDB接続ツールなど、プロジェクトで使うソフトウェア・ツールをDockerイメージで配布すると、プロジェクトメンバ内で統一が図れてGood。
- コラムとしてDockerは完全には
Vagrant
の代替にはならないので必ずしも移行は不要という話。 - Dockerの中にCLIツールを入れると、ホストへのインストールなしで使える。
- CLIツールのバージョンごとに別のDockerコンテナに入れておくと便利。
- OSのバージョンによって動きが違ったりするシェルの動作確認もコンテナ内でやるという手がある。
- Dockerのコンテナを複製する方法で高負荷限界を上げられるので、アプリケーションの負荷テストに使うのも効果的。本書ではPython製の
Locust
を紹介。
アプリ本体やミドルウェアに目が行っていたのでコマンドラインツールをDocker内で配布というのは思いつきませんでした……確かに言われてみると色々な使い道がありそうです。
そして最後は補足として、安全なDockerイメージの見分け方や作り方などセキュリティ関係、自前でDockerレジストリを作る方法、クラウド上での活用としてAWS Fargate
を用いたAWS ECS
でのコンテナ活用、コマンドまとめなどこれまた豊富なAppendixが並んでいます。本書で得た知識を元にECS/Fargate周りはもうちょっと理解を深めていきたいと思いました。
まとめ:Docker/Kubernetesの基礎から実践まで理解できる本
自分の場合は全体を掴むのが目的だったのですべてのコマンドを実際に叩いて……とはいかなかったのですが、だいぶ理解の解像度が上がりました。概念から基本の使い方、応用、運用や高度な利用まで踏み込んで一通り網羅してたくさんの情報が詰まっています。各所の感想にもある通りでコラムが豊富で、現場で役に立つ知見がたくさん書いてあります。
物理本は424ページだそうですが、コマンドの図解や実行結果のスクショも豊富なこと、章立てで内容が細分化されていることから、長くて力尽きそうになる印象はなかったですね。
コンテナ技術の根幹としてLinux周りのことも出てくるのでそのあたりがある程度分かること、Go言語の知識は不要ですが開発をある程度一通り分かっている人が主なターゲットかと思います。ですのでコンテナは初心者でもエンジニアとしては完全初心者よりもちょっと上の人が対象でしょうか。
さすがに評判の良い本は中もしっかりしている印象でした。Docker関連というとまず名前が挙がる良本ですが、発売の2018年から若干経った2021年現在でも十分役に立つことと思います。
関連リンク
著者の方自らによる、出版までの壮絶な道のりが分かる記事。表紙がポップ寄りなのは意図があるのですね。その後加筆するとしたらどうするかの話も読めます。
blog.stormcat.io blog.stormcat.io
各所のブログでもかなりの高評価の印象です。
- Docker始める人はまずこれ!書評「Docker/Kubernetes 実践コンテナ開発入門」 | DevelopersIO
「Docker/Kubernetes 実践コンテナ開発入門」がProduction環境でDockerを運用している人間にも良書だった - Glide Note
- 【書評】Docker/Kubernetes 実践コンテナ開発入門はまさに「実践」のための本です - まーぽんって誰がつけたの?
- 【書評】docker/kubernetes 実践コンテナ開発入門 | GROUP DEV BLOG | TECHNO MOBILE
- 書籍:Docker/Kubernetes 実践コンテナ開発入門 感想 - 追憶行
- Docker本 最初の一冊に「【書評】Docker/Kubernetes 実践コンテナ開発入門」|スクショはつらいよ