kubernetes の基礎的な勉強の一環で、Webアプリケーションの構築からアクセスまでを実践しています。
構成
クラスタの構築にはkind
を使用し、ローカル環境でDockerコンテナを使い3つのノードを起動します。(Dockerがインストールされていること)
アプリは Go の WebFramework Echo を使用して簡単なものを作成し、Deploymentで3つのPodを起動させます。
アクセスはLoadBalancerで各Podに分散するようになっています。
コードをGitLabで管理していたため、DockerイメージはGitLabのコンテナレジストリを使用しています。
Webアプリケーション作成
まずは直接ローカルでWebアプリケーションを起動して、動作確認してみます。
GETメソッドで2つエンドポイントを定義した簡単なものです。
- / : HelloWorld を返す
- /users : クエリパラメータで受け取った
name
,email
値を返す
main.go
package main import ( "net/http" "github.com/labstack/echo/v4" ) type User struct { Name string `json:"name" query:"name"` Email string `json:"email" query:"email"` } func main() { e := echo.New() e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) e.GET("/users", func(c echo.Context) error { u := new(User) if err := c.Bind(u); err != nil { return err } return c.JSON(http.StatusOK, u) }) e.Logger.Fatal(e.Start(":1323")) }
動作確認
2つのエンドポイントにアクセスし、レスポンスが返ってくることを確認
# アプリケーション起動 $ go run main.go # アクセス $ curl http://localhost:1323/ Hello, World! $ curl http://localhost:1323/users?name=hoge&email=hoge@example.com {"name":"hoge","email":"hoge@example.com"}
Dockerイメージ作成
kubernetesで起動させるためDockerイメージ化し、コンテナ上で起動できるか確認
Dockerfile
FROM golang:1.19.5-buster as build WORKDIR /app COPY go.mod ./ COPY go.sum ./ COPY server.go ./ RUN go mod download RUN go build -o /webapp FROM gcr.io/distroless/base-debian11 WORKDIR / COPY --from=build /webapp /webapp USER nonroot:nonroot ENTRYPOINT ["/webapp"]
コンテナで起動して動作確認
同じくコンテナでもアクセスを確認
# イメージビルド $ docker image build -t webapp . # コンテナ起動 $ docker run -p 1323:1323 webapp # アクセス $ curl http://localhost:1323/ Hello, World! $ curl http://localhost:1323/users?name=hoge&email=hoge@example.com {"name":"hoge","email":"hoge@example.com"}
コンテナレジストリへDockerイメージのpush
GitLab Runner を使用して、パイプライン実行時にイメージのbuild,コンテナレジストリへのpush を行います
Runner は自前で起動せずGitLabのSharedRunner
を有効化し、共有されているものを使用します
.gitlab-ci.yml
stages: - build image-build: stage: build tags: - docker image: docker:latest services: - docker:dind script: - docker info - docker build -t ${CI_REGISTRY}/kubernetes-web-app:${CI_COMMIT_SHA} . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker image push ${CI_REGISTRY}/kubernetes-web-app:${CI_COMMIT_SHA}
GitLab DeployTokenの発行
コンテナレジストリからDockerイメージを取得するため、DeployTokenを発行します
「Setting」⇒「Repository」⇒「Depoy tokens」
Pull an Image from a Private Registry | Kubernetes
kuberntesクラスタの起動
クラスタの定義はkind-cluster.yaml
で定義し,Dockerコンテナで起動。GitLabのコンテナレジストリから、Dockerイメージを取得するためconfig.jsonをマウントしてクラスタに認証情報を与えます。
config.json
発行したDeployTokenを{username}:{password}
の形式でbase64エンコードしたものをauth
に使用します。
Scopeはread_registry
が必要です。
# DeployToken base64エンコード $ echo -n {username}:{password} | base64 Z2l*******enZf # config.jaon { "auths": { "registry.gitlab.com": { "auth": "Z2l*******enZf" } } }
kind-cluster.yaml
config.json を各ノードにマウントし、GitLabの認証情報を与えます
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: webapp-cluster nodes: - role: control-plane extraMounts: - containerPath: /var/lib/kubelet/config.json hostPath: ./secret.json - role: worker extraMounts: - containerPath: /var/lib/kubelet/config.json hostPath: ./secret.json - role: worker extraMounts: - containerPath: /var/lib/kubelet/config.json hostPath: ./secret.json
ノードの定義ファイルが作成できたら、クラスタを起動していきます
$ kind create cluster --config kind-cluster.yaml
Pod,Serviceリソースの作成, アクセス確認
Deployment, Service にマニフェストを作成し、クラスタ上で起動します。kindで作成されるクラスタでは、LoadBalancerを作成してもコンテナ外からアクセス出来ないため、一時的にポートフォワーディングを行いアクセスする。
deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: webapp-deployment labels: app: webapp spec: replicas: 3 selector: matchLabels: app: webapp template: metadata: labels: app: webapp spec: containers: - name: webapp image: registry.gitlab.com/kubernetes-web-app:latest ports: - containerPort: 1323
service.yaml
apiVersion: v1 kind: Service metadata: name: webapp-service spec: ports: - port: 1323 targetPort: 1323 protocol: TCP name: http selector: app: webapp type: LoadBalancer
# リソース作成 $ kubectl apply -f deployment.yaml $ kubectl apply -f service.yaml # ポートフォワーディング $ kubectl port-forward service/webapp-service 1323:1323 # アクセス $ curl http://localhost:1323/ Hello, World! $ curl http://localhost:1323/users?name=hoge&email=hoge@example.com {"name":"hoge","email":"hoge@example.com"}