Dockerを本番環境で運用しようと考えるとどこにPrivateなDocker Registryを建てるかというのが結構大事になってきます。
GCSに対してアクセスを行います。
本番サーバ上などでDockerfileをビルドするのもできなくは無いですが、
できれば別サーバでビルドして、Docker Registryに突っ込んでおくほうがパターンとしては良さそうです。
できれば別サーバでビルドして、Docker Registryに突っ込んでおくほうがパターンとしては良さそうです。
今回はGoogle Cloud Storageをdocker-registryとして扱える
google/docker-registry
と Kubernetesを使って開発を行っていくパターンについて考えたいと思います。最終イメージ
最終的なイメージは以下になりました。
後半にこの環境の構築方法を書いていきます。
後半にこの環境の構築方法を書いていきます。
解説
環境周り
GCP上にはKubernetesをいれており、kubernetes-master 1台(図上には無し)と 複数台のkubernetes-minion(図上は2台)が存在しています。
各minion間のポートは開いており通信が可能です。
各minion間のポートは開いており通信が可能です。
また各minionにはGCEのサービスアカウントで
minionからGoogle Cloud Storageに対してのアクセスはfull権限持っている状態になっています。
storage-full
権限を付けており、minionからGoogle Cloud Storageに対してのアクセスはfull権限持っている状態になっています。
このKubernetesに対して
google/docker-registry
のPod(dockerコンテナ)を ReplicationControllerを利用して配置します。google/docker-registry
はGCSをdocker-registryとして利用できるGoogle製のDocker Registoryで minion上に配置されたgoogle/docker-registry
はminionに付与されたサービスアカウントを利用して、GCSに対してアクセスを行います。
例えば5000番ポートで
google/docker-registry
を立ち上げた場合[kubernetes-minion1] $ docker pull localhost:5000/my-app
とすればlocalhost:5000に立ち上がっている
GCS上に保存されている
google/docker-registry
が minionのサービスアカウント経由で認証し、GCS上に保存されている
my-app
イメージを取得することができます。podの配置とminion内の通信
ただ通常KubernetesではReplicationControllerのreplicas(podの配置数)をminion数以下にした場合、
どのminionにpodが配置されるかはわかりません。
全てのminionに
その為にサーバリソースを使うのもなんとなくもったいない気がします。
どのminionにpodが配置されるかはわかりません。
全てのminionに
google/docker-registry
を配置してもよいですが、その為にサーバリソースを使うのもなんとなくもったいない気がします。
そこでKubernetesのLoad Balancerである
Service
を使って各minion間を通信させます。Service
はKubernetesがminion内に作るProxyで、Podに対してPort Forwarding、Load Balancing機能を提供します。
例えばポート5555へのアクセスは、
どのminion内でもポート5555へのアクセスは、いずれかのminionにある
google/docker-registry
に向くようにServiceを設定すると、どのminion内でもポート5555へのアクセスは、いずれかのminionにある
google/docker-registry
に Forwardされるようになります。
つまり以下のようにすればminion1でもminion2でも
google/docker-registry
にアクセスしてくれるようになります。[kubernetes-minion2] $ docker pull localhost:5555/my-app
実際にはKubernetesで管理するはずのためlocalからkubernetesのマニフェストを作って実行するか、
以下のようにReplicationControllerを作ることになると思います。
以下のようにReplicationControllerを作ることになると思います。
[local] $ ./cluster/kubecfg.sh run localhost:5555/my-app 10 myAppController # kubecfg [OPTIONS] run image replicas controller
これでどのminionからでも
実際にはminionの数や、要件によって、
Kubernetesによって管理されているため、
replica数の調整もコマンド経由で上げ下げできます
google/docker-registry
を見れるようになりました。実際にはminionの数や、要件によって、
google/docker-registry
の数を調整することになると思いますが、Kubernetesによって管理されているため、
google/docker-registry
が落ちても立ち上げなおしてくれますし、replica数の調整もコマンド経由で上げ下げできます
[local] $ ./cluster/kubecfg.sh resize docker_registryController 10
開発時との関連
画像の右側の方のイメージです。
GCSをdocker-registryとして使えるようになることで、
開発者も同じように自分のPC内に
またGCS側でACLを設定できるため、更新できる開発者、できない開発者などの制御も(多分)可能です。
※開発者はDockerfileでビルドしろ−でもいい気もしますが。
開発者も同じように自分のPC内に
google/docker-registry
を立てて、imageを取得できるようになります。またGCS側でACLを設定できるため、更新できる開発者、できない開発者などの制御も(多分)可能です。
※開発者はDockerfileでビルドしろ−でもいい気もしますが。
またjenkins等のCIからも同様に
素敵ですね。
google/docker-registry
を立てればどうにでもできるようになります。素敵ですね。
環境の作成
Cloud Storage側
まずCloud Storage内にDocker Registry用のBucketを作成します。
※
※
DOCKER_REGISTRY_BUCKET_NAME
は任意の名前です。 世界レベルでユニークな値なので注意して下さい。[local] $ $ gsutil mb -l ASIA gs://DOCKER_REGISTRY_BUCKET_NAME
Compute Engine側
Kubernetesを建てる
kubernetesを立てますが、
上記で書いたようにminionからGCSにアクセスできるように
kubernetesを立ち上げる前であれば、
kubernetesのリポジトリ内にある
上記で書いたようにminionからGCSにアクセスできるように
storage-full
を付ける必要があります。kubernetesを立ち上げる前であれば、
kubernetesのリポジトリ内にある
cluster/gce/config-default.sh
のMINION_SCOPES
を以下のように修正して下さい。MINION_SCOPES="storage-full"
もちろんminionからのアクセスはRead-onlyにしたい場合はそれぞれ権限を調整して下さい。
あとはここに書いたようにKubernetesをGCE上に立てて下さい。
あとはここに書いたようにKubernetesをGCE上に立てて下さい。
※立ち上げてしまっている場合はScopeは修正できないのでminionを作り直す必要があります。
google/docker-registry
を建てる
次はこのKubernetes内に
まずはReplicationControllerのマニフェストファイルです。
google/docker-registry
を建てます。まずはReplicationControllerのマニフェストファイルです。
env
のGCS_BUCKETのvalueに先ほど作成したbucket名を設定して下さいdocker-registry-controller.yaml
id: dockerRegistryController kind: ReplicationController apiVersion: v1beta1 desiredState: replicas: 1 replicaSelector: name: docker_registry podTemplate: desiredState: manifest: version: v1beta1 id: docker_registry containers: - name: docker_registry image: google/docker-registry ports: - containerPort: 5000 hostPort: 5000 env: - name: GCS_BUCKET #先ほど作成したBucket名 value: DOCKER_REGISTRY_BUCKET_NAME labels: name: docker_registry labels: name: docker_registry
ReplicationControllerを作成します。
[local] $ ./cluster/kubecfg.sh -c docker-registry-controller.yaml create replicationControllers
google/docker-registry
のServiceを設定する
次にどのminionからでもアクセスできるようにServiceを作成します。
docker-registry-service.yaml
id: docker-registry kind: Service apiVersion: v1beta1 port: 5555 labels: name: docker_registry selector: name: docker_registry
[local] $ ./cluster/kubecfg.sh -c docker-registry-service.yaml create services
これでCompute Engine側の準備は完了です。
ローカルPC側
google/docker-registry
の準備
実際にローカルから
GCE側から取得するところまでやりたいのでローカルPCにも
google/docker-registry
経由でGCSにimageをpushし、GCE側から取得するところまでやりたいのでローカルPCにも
google/docker-registry
をいれます。
GCE川の場合はサービスアカウント経由で認証しましたが、
ローカル側の場合は自分のアカウントで認証させます。
ローカル側の場合は自分のアカウントで認証させます。
まず
google/docker-registry
内でgcloud auth login
を行います。[local] $ docker run -ti --name gcloud-config google/cloud-sdk gcloud auth login
次に上記ログイン済みコンテナ内でGCPプロジェクトを設定させます。
※
※
project
は自身のプロジェクトにして下さい。[local] $ docker run -ti --volumes-from gcloud-config google/cloud-sdk gcloud config set project
最後にこれらの設定済みimageを使って
※
google/docker-registry
を立ち上げます。※
GCS_BUCKET
は先ほど作成したBucket名を設定して下さい。[local] $ docker run -d -e GCS_BUCKET=DOCKER_REGISTRY_BUCKET_NAME -p 5000:5000 --volumes-from gcloud-config google/docker-registry
これでローカル側も準備完了です。
試してみる。
実際にローカルからGCSのdocker-registryにimageをpushして、
GCEのKubernetesから利用させてみます。
GCEのKubernetesから利用させてみます。
imageを作る
気分的にgoのwebアプリケーションにしてみます。
まずはDockerfileです。
google/golang-runtime
はDockerfileがあるディレクトリ内にある goファイルをビルドしてアプリケーションとして8080ポートで自動的に立ち会えげてくれる コンテナです。Dockerfile
From google/golang-runtime
次に使うGoファイル 細かいところは気にしないでください。
main.go
package main import ( "fmt" "net/http" "os" ) func main() { http.HandleFunc("/", index) http.ListenAndServe(":8080", nil) } func index(rw http.ResponseWriter, req *http.Request) { hostname, err := os.Hostname() if err != nil { fmt.Fprintf(rw, "%s %s", os.Getenv("SERVICE_HOST"), os.Getenv("DOCKER_REGISTRY_SERVICE_PORT")) } else { fmt.Fprintf(rw, "%s %s %s", hostname, os.Getenv("SERVICE_HOST"), os.Getenv("DOCKER_REGISTRY_SERVICE_PORT")) } }
これらをbuildします。
[local] $ docker build -t localhost:5000/my-app .
GCSへpushする
次にGCSへpushします。
[local] $ docker push localhost:5000/my-app
pushを行うとGCS側にimageがpushされます。
GCE側から使う
KubernetesのReplicationController経由で取得します。
マニフェストを作成します。
マニフェストを作成します。
先ほどと異なりimageの指定が
localhost:5000/my-app
ではなく、localhost:5555/my-app
になっています。my-app-controller.yaml
id: myAppController kind: ReplicationController apiVersion: v1beta1 desiredState: replicas: 4 replicaSelector: name: myapp podTemplate: desiredState: manifest: version: v1beta1 id: myapp containers: - name: myapp image: localhost:5555/my-app ports: - containerPort: 8080 hostPort: 80 labels: name: myapp labels: name: myapp
これをKubernetesへ登録します。
[local] $ ./cluster/kubecfg.sh -c my-app-controller.yaml create replicationControllers
しばらく待つとminion内で
実際に中に入ってみてみましょう
my-app
イメージが立ち上がり始めます。実際に中に入ってみてみましょう
[local] $ gcloud compute ssh kubernetes-minion-1 [kubernetes-minion-1] $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6221837e9d19 localhost:5555/my-app:latest "/bin/go-run" 3 hours ago Up 3 hours k8s--my_-_app.24d4f934--4631a018_-_37ba_-_11e4_-_9aa0_-_42010af07411.etcd--3f808d5b afaec6e95e26 kubernetes/pause:latest "/pause" 3 hours ago Up 3 hours 0.0.0.0:80->8080/tcp k8s--net.23bc7648--4631a018_-_37ba_-_11e4_-_9aa0_-_42010af07411.etcd--593bb76d a02f3b43342f kubernetes/pause:latest "/pause" 21 hours ago Up 21 hours 0.0.0.0:4194->8080/tcp k8s--net.14587872--cadvisor_-_agent.file--d29bb165 [kubernetes-minion-1] $ exit [local] $ gcloud compute ssh kubernetes-minion-2 [kubernetes-minion-2] $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51da3e224841 localhost:5555/my-app:latest "/bin/go-run" 3 hours ago Up 3 hours k8s--my_-_app.4866f942--69dc2f50_-_37ba_-_11e4_-_9aa0_-_42010af07411.etcd--54dd2fcb e67a30486a10 kubernetes/pause:latest "/pause" 3 hours ago Up 3 hours 0.0.0.0:80->8080/tcp k8s--net.23bc7648--69dc2f50_-_37ba_-_11e4_-_9aa0_-_42010af07411.etcd--5a8179a6 04c624dd7079 google/docker-registry:latest "/bin/sh -c 'cd /doc" 21 hours ago Up 21 hours k8s--dockerregistry.8d75af88--491142e3_-_3722_-_11e4_-_9aa0_-_42010af07411.etcd--04646fdc 7042f1deb6d8 kubernetes/pause:latest "/pause" 21 hours ago Up 21 hours 0.0.0.0:5000->5000/tcp k8s--net.c9fe769a--491142e3_-_3722_-_11e4_-_9aa0_-_42010af07411.etcd--90f92c41 9bea90554dd3 google/cadvisor:latest "/usr/bin/cadvisor -" 21 hours ago Up 21 hours k8s--cadvisor.20accae6--cadvisor_-_agent.file--64431513 4fe299791621 kubernetes/pause:latest "/pause" 21 hours ago Up 21 hours 0.0.0.0:4194->8080/tcp k8s--net.14587872--cadvisor_-_agent.file--923eced4
実際にdocker-registryが立ち上がっていないminionでもmy-appを取得できていますね。
これでprivate registryを使ったローカル or jenkins → GCS → GCEという形が作れました。
これでprivate registryを使ったローカル or jenkins → GCS → GCEという形が作れました。
まとめ
GCSを使ってprivateのimageを共有できるのはかなりいいですね。
実際の運用では例えば開発者とminionからはGCSへのpushはread-onlyな状態にして、
Dockerfileのみをコミット可能、
imageのpushはjenkinsのみから実施できるようにしたりすると、危険性も減りそうです。
実際の運用では例えば開発者とminionからはGCSへのpushはread-onlyな状態にして、
Dockerfileのみをコミット可能、
imageのpushはjenkinsのみから実施できるようにしたりすると、危険性も減りそうです。
コンテナを利用していることでポータブルにdocker-registryを作成することができるので、
開発者に配ったりも楽になるはずです。
開発者に配ったりも楽になるはずです。
0 件のコメント:
コメントを投稿