k8s自体も実際の業務用途で使ったことはないし、今回業務で本格利用するにあたって一度理解しておきたくやったことをまとめておく。
長いので2つに分けたうちの1つ目。
やったこと
- GKE基本を学習
- 自作のgoのイメージをContainer Registryに登録し、クラスタにデプロイ、ローリングアップデートまで試す
(今回はここまで)
(以降は次の記事に書く)
3. Spinnaker on Google Cloud Platformのインストール
4. Pub/Subに作られたTopicとSubscription経由で、Container RegistryへのイメージPUSHを検出できることの確認
5. SpinnakerがPub/Sub経由でMessageをSubscribeし、GKEのイメージを更新するためのPipelineを作る
gcloudコマンド初期設定
まずプロジェクトとZoneをセットする。
% gcloud config set project ***
Updated property [core/project].
% gcloud config set compute/zone us-central1-c
基本を覚えるためGKEクイックスタートをやってみる
クラスタの構成はデフォルトで一旦進める。
$ gcloud container clusters create test-cluster-1
$ gcloud container clusters list
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
test-cluster-1 us-central1-c 1.14.10-gke.27 [MASTER-IP] n1-standard-1 1.14.10-gke.27 3 RUNNING
とりあえず出来た。
この時点ではkubectlの操作対象が未設定。
% kubectl config current-context
error: current-context is not set
作成したclusterについて認証情報を取得する。
$ gcloud container clusters get-credentials test-cluster-1
Fetching cluster endpoint and auth data.
kubeconfig entry generated for test-cluster-1.
この状態で改めて以下を実行。
% kubectl config current-context
gke_[PROJECT-ID]_us-central1-c_test-cluster-1
このように操作対象clusterがセットされた。
実際には こういう事 が行われているらしいですね。
次にサンプルにあるDeploymentを作成してみる。
% kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0
deployment.apps/hello-server created
この状態ではservicesが外にされされていないのでこんな感じになっている。
% kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-server 1/1 1 1 7s
% kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 10m
ここで出てくるCLUSTER-IPはなんのIPだろうと思うわけだが、gcloudでみたclusterの情報が↓。
% gcloud container clusters describe test-cluster-1
addonsConfig:
kubernetesDashboard:
disabled: true
networkPolicyConfig:
disabled: trueclusterIpv4Cidr: 10.24.0.0/14
(略)
servicesIpv4Cidr: 10.27.240.0/20 <--これ
shieldedNodes: {}
status: RUNNING
subnetwork: default
zone: us-central1-c
service側のCIDRの中からIPが自動アサインされているのだろうと予測しました。
podとserviceがそれぞれ使うレンジなんですね。
こちら に書かれていました。
ただ現在はserviceが外にさらされていないので、外部からは叩けない。
ということで、↑で作ったものを外に公開。
% kubectl expose deployment hello-server --type LoadBalancer --port 80 --target-port 8080
service/hello-server exposed
この状態で以下を実行してみる。
% kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-server LoadBalancer 10.27.244.156 <pending> 80:31116/TCP 9s
kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 3m
EXTERNAL-IPが <pending>
の場合は数分かかることもあるらしいので何回か実行してみる。
% kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-server LoadBalancer 10.27.244.156 [払い出されたIP] 80:31116/TCP 99s
kubernetes ClusterIP 10.27.240.1 <none> 443/TCP 4m30s
払い出されたので外からつないでみる。
% curl [払い出されたIP]
Hello, world!
Version: 1.0.0
Hostname: hello-server-7f8fd4d44b-rch6q
上手くつながった。
ということで一旦クラスタごと消しておく。
% gcloud container clusters delete
自作のイメージをContainer Registryに登録
簡単なgoアプリケーション
上記のクイックスタートにあるようなシンプルなWebアプリケーションを作るイメージをContainer Registryに登録してみます。
コードは以下とします。
main.go
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, world!\n"))
w.Write([]byte("Version: 1.0.0\n"))
}
go run main.go
してから実際に接続するとこんな感じ。
% curl localhost:8080
Hello, world!
Version: 1.0.0
Dockerイメージ化する
次にmain.goと同じディレクトリにDockerfileを作る。
FROM golang:latest
RUN mkdir /go-practice
COPY main.go /go-practice
CMD ["go", "run", "/go-practice/main.go"]
一旦適当な名前でビルドして動作確認。
% docker build -t my-go-practice .
% docker run -it -p 8080:8080 my-go-practice
この状態でlocalhostにcurl。
% curl localhost:8080
Hello, world!
Version: 1.0.0
ちなみに作られたイメージは以下。
ローカル的には my-go-practice:latest
としてある。
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-go-practice latest 2bdb240e98e4 6 minutes ago 809MB
Container Registryに登録(PUSH)
これで一旦イメージとして成立することはわかったのでContainer RegistryにPUSHしてみる。
クイックスタート をみながら実施。
まず認証を取る。
% gcloud auth configure-docker
次にContainer RegistryにPUSH。
% docker push gcr.io/[PROJECT-ID]/my-go-practice:1.0
The push refers to repository [gcr.io/[PROJECT-ID]/my-go-practice]
An image does not exist locally with the tag: gcr.io/[PROJECT-ID]/my-go-practice
イメージにtagをつけないとこうなるらしい。
ということでそれをやる。タグは 1.0
にする。
latestタグ運用はk8s上推奨されてないんですね。(実際ローリングアップデートできなかったので気づいた)
こちら が参考になりました。
% docker tag my-go-practice gcr.io/[PROJECT-ID]/my-go-practice:1.0
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-go-practice latest 115573622dc3 3 minutes ago 809MB
gcr.io/[PROJECT-ID]/my-go-practice 1.0 115573622dc3 3 minutes ago 809MB
よし、タグが付いたのでContainer RegistryにPUSH。
% docker push gcr.io/[PROJECT-ID]/my-go-practice:1.0
The push refers to repository [gcr.io/[PROJECT-ID]/my-go-practice]
a55b08a710fd: Pushed
ccd59ad1b6c1: Pushed
feae5ce26f02: Layer already exists
29a23d067e48: Layer already exists
1af88e92b20b: Layer already exists
d35c5bda4793: Layer already exists
a3c1026c6bcc: Layer already exists
f1d420c2af1a: Layer already exists
461719022993: Layer already exists
latest: digest: sha256:df8c5ff70adf2232844e2789db8365a01bc7aa7c34b15776166f34963665ec19 size: 2209
無事PUSH出来ているかを確認してみる。
% gcloud container images list
NAME
gcr.io/[PROJECT-ID]/my-go-practice
Only listing images in gcr.io/[PROJECT-ID]. Use --repository to list images in other repositories.
大丈夫そうなので次にこれを使ってデプロイをしてみる。
Container Registryのイメージを利用したDeploymentを作成
では新しくそれを使ったデプロイを試してみる。
今回は以下のようにDeploymentを作って更に外部公開する。
% kubectl create deployment hello-server --image=gcr.io/[PROJECT-ID]/my-go-practice:1.0
% kubectl expose deployment hello-server --type LoadBalancer --port 80 --target-port 8080
上手く行ったのでcurlしてみる。
% curl 34.71.197.192
Hello, world!
Version: 1.0.0
想定通りの動作をしたのでOK。
Container Registryのイメージを更新してからローリングアップデート
では次にContainer Registryのイメージ更新がかかった場合に、Deploymentが勝手にローリングアップデートをしてくれることを確認する。
Deploymentを作った時のイメージ指定は --image=gcr.io/[PROJECT-ID]/my-go-practice:1.0
なので、このタグのイメージが置き換われば切り替わるはず・・・と言う想定。
まずmain.goを以下のように修正。
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, world!\n"))
w.Write([]byte("Version: 2.0.0\n")) // <-- ここ
}
この状態でローカルのイメージを削除し作り直す。更にタグを追加。
% docker build -t my-go-practice .
% docker tag my-go-practice gcr.io/[PROJECT-ID]/my-go-practice:2.0
GCRにPUSHする。
% docker push gcr.io/[PROJECT-ID]/my-go-practice:2.0
% gcloud container images list
NAME
gcr.io/[PROJECT-ID]/my-go-practice
次にserviceのイメージを変更して、ローリングアップデートがかかるのをみておく。
% kubectl set image deployments/hello-server my-go-practice=gcr.io/[PROJECT-ID]/my-go-practice:2.0
deployment.extensions/hello-server image updated
ちなみにコマンドの書式は、
% kubectl set image <deployment> <container name>=<image>
であり、 container name の部分は、 kubectl describe deployments hello-server
とかで取れる。
% kubectl describe deployments hello-server
Name: hello-server
Namespace: default
CreationTimestamp: Tue, 21 Apr 2020 09:28:06 +0900
Labels: app=hello-server
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=hello-server
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=hello-server
Containers:
my-go-practice: <-- ここ
Image: gcr.io/[PROJECT-ID]/my-go-practice:2.0
(略)
試しに接続してみるとこうなったのでアップデートOK。
% curl [EXTERNAL-IP]
Hello, world!
Version: 2.0.0
とりあえず今回はここまで。
次回以降Spinnakerを入れてPipelineを試していく。