GKE でプリエンプティブルの VM を利用すると Kubernetes クラスタ自体の料金はとても安いのですが、LoadBalancer を使うと約 18 ドルがかかります。ここを抑えるためにいろいろ調べていたところ great article を偶然見つけました。とても感謝です。
この投稿のとおりにすれば 18 ドルを 8 ドル(e2-micro)に抑えることができそうです。
自分の理解ですが、この仕組みはプリエンプティブルではない VM ノードを 1 台追加して、そこで traefik を実行して、 traefik からプリエンプティブルの VM ノードにルーティングしているのだと思います。 traefik を実行するノードをプリエンプティブルではないようにしているのは意図せずダウンしては困るからでしょう。また、このノードに割り振った IP アドレスを Cloud DNS に設定することになります。
traefik はリバースプロキシです。ルーティング設定を動的に変更できたりするすごいやつです。
実行に際しての注意点ですが、現時点では f1-micro で kubernetes クラスタを構築できないので e2-micro に変えておきます。
以下、自分用のメモ
1 2 terraform init terraform apply
途中のAggressive optimizationsの項目はスキップしました。
1 2 cd k8s/kujilabo-blog kubectl apply -f namespace.yaml
k8s/kujilabo-blog/namespace.yaml 1 2 3 4 5 6 kind: Namespace apiVersion: v1 metadata: name: kujilabo-blog labels: name: kujilabo-blog
1 2 3 gcloud iam service-accounts list gcloud iam service-accounts keys create keys/kubeip-key.json --iam-account kubeip-serviceaccount@cocotola.iam.gserviceaccount.com kubectl create secret generic kubeip-key --from-file=keys/kubeip-key.json -n kube-system
1 2 3 4 cd k8s/kubeip kubectl apply -f serviceaccount.yaml kubectl apply -f configmap.yaml kubectl apply -f deployment.yaml
正常に kubeip が稼働すると外部 IP で定義した static-ingress の IP がノードと関連づきます。
1 2 3 4 5 cd k8s/traefik kubectl apply -f namespace.yaml kubectl apply -f serviceaccount.yaml kubectl apply -f configmap.yaml kubectl apply -f resource.yaml
1 2 gcloud iam service-accounts keys create cert-manager-key.json --iam-account cert-manager@cocotola.iam.gserviceaccount.com kubectl create secret generic clouddns-service-account --from-file=cert-manager-key.json=cert-manager-key.json -n kujilabo-blog
該当のネームスペースに clouddns-service-account が登録されていることを確認。
1 kubectl get secrets -n kujilabo-blog
1 2 NAME TYPE DATA AGE clouddns-service-account Opaque 1 3s
Cloud DNS の初期設定 Google Domains で取得しているドメインの DNS の設定を開き、Use custom name serversを選択し、GCP の NS の値を設定します。
例:
1 2 3 4 ns-cloud-c1.googledomains.com. ns-cloud-c2.googledomains.com. ns-cloud-c3.googledomains.com. ns-cloud-c4.googledomains.com.
以降、DNS の設定は Cloud DNS の設定画面からおこないます。
cert-manager をインストール 1 2 kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.1/cert-manager-legacy.yaml kubectl get all -n cert-manager
1 kubectl apply -f issuer.yaml
cert-kujilabo/issuer.yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: kujilabo-issuer namespace: kujilabo-blog spec: acme: email: your@mail server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: kujilabo-issuer solvers: - dns01: cloudDNS: project: cocotola serviceAccountSecretRef: name: clouddns-service-account key: cert-manager-key.json
1 kubectl apply -f certificate.yaml
cert-kujilabo/certificate.yaml 1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: kujilabo-com namespace: kujilabo-blog spec: secretName: kujilabo-com-tls issuerRef: name: kujilabo-issuer dnsNames: - kujilabo.com - www.kujilabo.com
状況を確認するコマンド
1 2 kubectl describe certificate -n kujilabo-blog kubectl describe certificaterequest -n kujilabo-blog
1 kubectl get secrets -n kujilabo-blog
1 kujilabo-com-rq9dq Opaque 1 81s
1 kujilabo-com-tls kubernetes.io/tls 2 11s
1 2 cd k8s/traefik kubectl apply -f route-kujilabo-blog.yaml
traefik/route-kujilabo-blog.yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: kujilabo-blog namespace: kujilabo-blog spec: entryPoints: - web routes: - match: PathPrefix(`/`) kind: Rule services: - name: kujilabo-blog port: 80 --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: kujilabo-blog-tls namespace: kujilabo-blog spec: entryPoints: - websecure routes: - match: PathPrefix(`/`) kind: Rule services: - name: kujilabo-blog port: 80 tls: secretName: kujilabo-com-tls
kuberenetes.yaml.tpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 apiVersion: apps/v1 kind: Deployment metadata: name: kujilabo-blog namespace: kujilabo-blog labels: app.kubernetes.io/name: kujilabo-blog app.kubernetes.io/part-of: kujilabo-blog spec: replicas: 1 selector: matchLabels: run: kujilabo-blog app.kubernetes.io/name: kujilabo-blog app.kubernetes.io/part-of: kujilabo-blog template: metadata: labels: run: kujilabo-blog app.kubernetes.io/name: kujilabo-blog app.kubernetes.io/part-of: kujilabo-blog spec: nodeSelector: cloud.google.com/gke-nodepool: web-pool containers: - image: gcr.io/cocotola/kujilabo-blog-app:COMMIT_SHA imagePullPolicy: IfNotPresent name: kujilabo-blog ports: - name: http containerPort: 80 - name: https containerPort: 443 --- apiVersion: v1 kind: Service metadata: name: kujilabo-blog namespace: kujilabo-blog spec: type: ClusterIP ports: - protocol: TCP name: tcp-80 port: 80 targetPort: 80 - protocol: TCP name: tcp-443 port: 443 targetPort: 443 selector: app.kubernetes.io/name: kujilabo-blog app.kubernetes.io/part-of: kujilabo-blog