イメージビルド(Dockerfile)の何がいやなのか
- Dockerfile自体の管理をしないといけない
- Dockerfileとイメージの対応を管理しないといけない
- イメージにアップデートが必要な場合、そのイメージをBASEにしているイメージもビルドしなおす必要が出てくる
- イメージ継承が多いと、再ビルド作業が連鎖で発生していく
Kubernetesの機能でだいたい出来るんじゃないか?疑惑
- Dockerfileの次のような使い方をKubernetesの機能で置き換えていきます
- RUNでアプリの追加インストール(apt, yum)
- ADD,COPYでスクリプトを入れる
- CMD, ENTRYPOINTで起動時のコマンド変更
- USERで実行ユーザー・グループを変える
- 次の使い方は置き換え断念します
- RUNでコンパイル
- Kubernetesの機能でやるとPod起動時にコンパイルすることになります。起動が遅くなります
- コンパイル済みのアプリを組み込んだイメージを作成するしかなさそうです
- RUNでコンパイル
「RUNでアプリの追加インストール」の置き換え
- イメージ内にインストールするのではなく、インストール済みのイメージを組み合わせるといけそうです
- KubernetesのPodには複数のコンテナを含めることが出来ます
- サイドカーパターンと呼ばれるものです。
- この機能を使えば、 アプリのインストールをコンテナの組み合わせに置き換え出来そうです
- KubernetesのInit Containers機能を使うと、コンテナAで処理実行→コンテナBで処理実行→・・・といったフローを組むことが出来ます
- KubernetesのPodには複数のコンテナを含めることが出来ます
サイドカーパターンの補足
- 別々のコンテナがネットワークスタック(NIC、loopback interface等)を共有します
- 各コンテナのアプリの待ち受けポートは、localhostの待ち受けポートとして相互通信できます
- container1がポート80で待ち受ける場合、container2から
localhost:80
でcontainer1にアクセスできます- Pod内のコンテナ同士で待ち受けポートが被らないようにしないといけません
- これだけだとファイルシステムが分離されていてコンテナ間でファイル共有ができません。
- EmptyDirを作ることで共有ボリュームを持てます
「ADD,COPYでスクリプトを入れる」の置き換え
- configMapでスクリプトファイルを作ってしまいましょう
- configMap自体はその名の通り、設定ファイルを配布するための機能です
- 実態としてはテキストファイルを配布する機能なので、スクリプトを配布するのにも使えます
「CMD, ENTRYPOINTで起動時のコマンド変更」の置き換え
- これはPodのYAMLでコマンドを指定すればいいでしょう
「USERで実行ユーザー・グループを変える」の置き換え
- これは
securityContext
のrunAsUser
,runAsGroup
,supplementalGroups
を使えばいけそうです- 注意: Dockerの仕様上、イメージの中に
runAsGroup
で指定したグループが存在しない時はrootグループで実行されます- その場合は起動時に、
groupadd
してからrunuser
コマンドを実行してやればいいと思います
- その場合は起動時に、
- 注意: Dockerの仕様上、イメージの中に
実際にやってみる
Tensorboardにbasic認証をつけてみる
- TensorboardはDeep Learningの結果をグラフで表示してくれるwebサーバーです
- Tensorboardは認証をサポートしません ので、basic認証するにはnginx等が必要です
- もしイメージビルドでやるなら、TensorboardイメージへのNginxインストールをRUNでした後に、設定ファイルをcopyすることになります
- イメージビルドの代わりに、解説したサイドカーパターンを使ってみます
- TensorboardイメージとNginxイメージを使います
- あとはKubernetesのyamlで実装してみます
各YAML
nginx-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
auth.conf: |
server {
listen 80 default_server;
location / {
auth_basic "Restricted";
auth_basic_user_file auth.htpasswd;
proxy_pass http://localhost:6006;
proxy_read_timeout 900;
}
}
auth.htpasswd: |
foo:$apr1$odHl5EJN$KbxMfo86Qdve2FH4owePn.
tensorboard-basic-auth.yml
apiVersion: v1
kind: Pod
metadata:
name: tensorboard-basic-auth
labels:
app: tensorboard-basic-auth
spec:
volumes:
- name: config-volume
configMap:
name: nginx-config
containers:
- image: tensorflow/tensorflow:1.12.0-py3
name: tensorflow
command: ["/usr/local/bin/tensorboard", "--logdir", "path/to/logs"]
- image: nginx:alpine
name: nginx
ports:
- name: nginx
containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /tmp/config
command:
- sh
- "-c"
- |
cp /tmp/config/auth.conf /etc/nginx/conf.d/auth.conf
cp /tmp/config/auth.htpasswd /etc/nginx/auth.htpasswd
rm /etc/nginx/conf.d/default.conf
nginx -g "daemon off;"
tensorboard-service.yml
apiVersion: v1
kind: Service
metadata:
name: tensorboard-basic-auth
labels:
app: tensorboard-basic-auth
spec:
type: NodePort
ports:
- name: nginx
port: 80
nodePort: 30036
selector:
app: tensorboard-basic-auth
- 備考
- ここを参考に作りました
- Nginxの設定ファイルの解説はここ にあります
- 上記のyamlの場合は「foo/bar」でログインできます
- configMapで2つの設定ファイル
auth.conf
、auth.htpasswd
を定義しています- それらを
/tmp/config
にマウントしたのち、cpで本来置くべき場所に配置しています- configMapのマウントはReadOnlyなので、cpをmvにすると失敗します
- 直接配置先にマウントさせることもできるはずですが、YAMLの記述が増えるので今回はやっていません
-
localhost:6006
の6006はTensorboardコンテナのデフォルト待ち受けポートです
- それらを
- Tensorboardについて、本来はyaml中にある「path/to/logs」の部分に学習ログを置く必要がありますが、今回は省略しています
- その他いろいろ省略しています
- https対応
- 認証情報部分はConfigMapよりSecretの方がいい
作成
kubectl create -f nginx-config.yml
kubectl create -f tensorboard-basic-auth.yml
kubectl create -f tensorboard-service.yml
動作確認
- basic認証画面が出てきます
- foo/bar以外を入れると認証失敗します
- foo/barを入れるとtensorboardが表示されます
その他の使い方の参考
- init containers
- Kubernetes 初期化専用コンテナで、ポッド内共有ボリュームにデータを取り込む がInitContainerの参考になります
- mysqlクラスタの初期化
- ConfigMapのスクリプト実行
-
Kubernetes Log Management using Fluentd as a Sidecar Container and preStop Lifecycle Hook- Part IV
- configMapでprestop.shというスクリプトが出てきます
-
Kubernetes Log Management using Fluentd as a Sidecar Container and preStop Lifecycle Hook- Part IV
- ユーザー変更
まとめ
- コンパイル以外のDocker build作業はだいたいなくせそうです
- Docker buildをなくしたいかどうかは個人の趣味によりそうですが、私はあまりビルドしたくありません
- 冒頭に書いた理由
- kubernetes上で設定ファイルの確認・変更がしやすいです
- 設定ファイル変更のたびにビルドとかしなくて済みます
- デメリットとしてイメージを探す作業は生じますが。。