taxin's notes

読書、勉強メモ etc.

CircleCI + KustomizeでKubernetes環境のCI/CD Pipelineを作る

はじめに

@taxin_ttと申します。

CI/CD Pipelineの実装+GCP / CircleCIの勉強も兼ねて、GKEのKubernetesクラスター上にサンプルアプリをDeployするCI/CD Pipelineを実装してみました。

構成

今回は、Circle CI + KustomizeでCI/CD Pipelineを実装しました。
(Deploy先のKubernetesクラスターもTerraformで作成できるようにしています。)

f:id:taxintt:20200617080141p:plain

大まかな処理の流れは下記の通りです。

  1. コードの変更をApp repo(Stgブランチ)にPush
  2. MasterブランチへのMergeをトリガーとしてContainer ImageをBuild
  3. BuildしたContainer ImageをContainer RegistryにPush
  4. Manifest repo内のImage tagの書き換え
  5. 修正したManifest ファイルをKubernetes Clusterに反映

このフローはWeaveworksが出しているGitOps PipelineのExampleとほぼ同じような構成にしています。
(Circle CIがクラスタにManifest repoの変更を反映する(Push)の方式をとっているので、実際にはGitOpsではなくCIOpsの構成になっています。) www.weave.works

レポジトリの構成

レポジトリはアプリ用のrepoとマニフェスト用のrepoに分けています。
動作確認自体はできていますが、未完成の部分も一部あります。

github.com

github.com

ブランチの構成

上記の2つのレポジトリでは、Prodction環境用のmasterブランチとStaging環境用のstgブランチの2つを用意しています。

最初に、 DeveloperがコードをstgブランチにPushします。
(実際には、さらに別のブランチを切ってstgブランチに対するPRをMergeするなどして、Staging環境用のブランチに変更を反映することになると思います。)

f:id:taxintt:20200617095603p:plain

App Repo (stgブランチ) へのPushをトリガーとして、Circle CIのJobが起動してManifest Repo (stgブランチ) のImage tagを書き換えます。

f:id:taxintt:20200617095824p:plain

App Repo (stgブランチ) の変更内容をmasterブランチにMergeします。
上記のMasterブランチへのMergeをトリガーとして、Manifest RepoのPR (stgブランチ → masterブランチ) を作成します。

f:id:taxintt:20200617101211p:plain

App repoのCircle CIのJob定義

それぞれのJobごとに分割して説明します。

Container ImageのBuildとRegistryへのPush

build_and_push_image では、Container ImageのBuildとRegistryへのPushを行います。
また、OrbsとしてSlackとの連携機能を利用しているので、Jobが完了した後に成功/失敗の通知をSlackで行います。

Container ImageをGCR(Google Container Registry)にPushするためには、Service Account(SA)を利用するため事前にGCPのコンソールでService Accountを作成しておきます。

circleci.com

Service AccountにはRegistryへのPush権限を付与する必要があるため、「ストレージ管理者」の権限を付与しておきます。
最後に、Service Accountの作成時にキーファイルをダウンロードして、その中身をbase64エンコードした上でCircle CIの環境変数(${ACCT_AUTH})として登録しておきます。

cloud.google.com

ImageのTagに関しては、直近のコミットハッシュをCircle CIの環境変数 ($CIRCLE_SHA1) から取得してTagとして利用します。

circleci.com

version: 2.1
orbs:
  slack: circleci/slack@3.4.2
jobs:
  build_and_push_image:
    docker:
      - image: google/cloud-sdk
    working_directory: /go/src/github.com/TaxiN/sample-app-ci
    steps:
      - setup_remote_docker:
          version: 18.06.0-ce
      - checkout
      - run:
          name: Authenticate for pushing image to GCR
          command: |
            echo ${ACCT_AUTH} | base64 -d > ${HOME}/account-auth.json
            gcloud auth activate-service-account --key-file=${HOME}/account-auth.json
            gcloud --quiet config set project ${GCP_PROJECT}
            gcloud --quiet config set compute/zone ${CLOUDSDK_COMPUTE_ZONE}
            gcloud --quiet auth configure-docker         
      - run:
          name: Build docker image and set image tag
          command: docker build -t ${GCR_REPO}/${IMAGE_NAME}:$CIRCLE_SHA1 .
      - run:
          name: Push image to repository
          command: docker push ${GCR_REPO}/${IMAGE_NAME}:$CIRCLE_SHA1
      - slack/status:
          include_project_field: true
          success_message: ':circleci-pass: Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          failure_message: ':circleci-fail: Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          webhook: ${SLACK_WEBHOOK}


マニフェストファイルのImage tagの書き換え

push_changes_to_manifest_repo のJobでは、Manifest repoにあるマニフェストファイルのImage tagの書き換えを行います。

マニフェストファイルはKustomizeを用いて管理しています。
Kustomizeではkustomize editコマンドでImage tagの書き換えを容易に行うことができます。

github.com

Image tagの書き換えを行った後に、変更内容をcommit + pushしています。
App repoではなく、cloneしてきたManifest repoに対して変更をpushするのでremoteの設定を変更しておきます。

また、Manifest repoへのpushができるようにManifestのGitHub repositoryでDeploy keyを作成して、Circle CI側に登録しておきます。
登録したDeploy keyはadd_ssh_keysのstepを実行することで、Job用のコンテナに対して鍵を登録します。

qiita.com

circleci.com

  push_changes_to_manifest_repo:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: apt-get update for wget
          command: |
            apt-get update
            apt-get install -y wget
      - run:
          name: install kubectl
          command: |
            curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
            mv kubectl /usr/local/bin
            chmod +x /usr/local/bin/kubectl
      - run:
          name: install kustomize
          command: |
            wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.4/kustomize_v3.5.4_linux_amd64.tar.gz
            tar xvzf kustomize_v3.5.4_linux_amd64.tar.gz
            mv kustomize /usr/local/bin
            chmod +x /usr/local/bin/kustomize
      - run:
          name: set config of github repo
          command: |
            git config --global user.email "circleci-user@noreply.github.com"
            git config --global user.name "circleci-user"
      - run:
          name: clone kubernetes manifests repo
          command: |
            git clone --depth 1 -b stg git@github.com:TaxiN/sample-manifest-repo.git
            cd ./sample-manifest-repo
            git remote set-url origin git@github.com:TaxiN/sample-manifest-repo.git
      - run:
          name: edit kubernetes manifests
          command: |
            cd ./sample-manifest-repo/overlays/staging
            kustomize edit set image ${GCR_REPO}/${IMAGE_NAME}:$CIRCLE_SHA1
      - add_ssh_keys:
          fingerprints:
            - "<fingerprints>"
      - run:
          name: commit and push the changes
          command: |
            cd ./sample-manifest-repo
            git add .
            git commit -m "Updating image tag ${GCR_REPO}/${IMAGE_NAME}:$CIRCLE_SHA1"
            git branch --set-upstream-to=origin/stg stg
            git push origin stg


Manifest repoでのPull Request (stgmaster)の作成

create_pr_in_manifest_repo のJobでは、Manifest repoに対してPull Requestを作成します。
このJobはApp repoでのMasterブランチへのMergeをトリガーとして実行されます。

Pull Requestの作成には、hubを利用します。
--base--headでブランチを指定することでPRの設定を行います。

hub.github.com

create_pr_in_manifest_repo:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: install hub
          command: |
            curl -sSLf https://github.com/github/hub/releases/download/v2.8.3/hub-linux-amd64-2.8.3.tgz | \
            tar zxf - --strip-components=1 -C /tmp/ && \
            mv /tmp/bin/hub /usr/local/bin/hub
      - run:
          name: set config of github repo
          command: |
            git config --global user.email "circleci-user@noreply.github.com"
            git config --global user.name "circleci-user"
      - add_ssh_keys:
          fingerprints:
            - "<fingerprints>"
      - run:
          name: create pull request
          command: |
            git clone --depth 1 -b stg git@github.com:TaxiN/sample-manifest-repo.git
            cd ./sample-manifest-repo
            hub pull-request \
              --message="Deploying image ${GCR_REPO}/${IMAGE_NAME}:$CIRCLE_SHA1 \
              Built from commit ${COMMIT_SHA} of repository sample-app-ci \
              Author: $(git log --format='%an <%ae>' -n 1 HEAD)" \
              --base=${CIRCLE_PROJECT_USERNAME}:master \
              --head=${CIRCLE_PROJECT_USERNAME}:stg


Manifest repoのCircle CIのJob定義

Manifest repoのJobでは、Master, stgブランチでの変更をトリガーとしてKubernetesクラスターに変更を反映します。
今回は一つのクラスタ内でprd, stgとそれぞれの環境用のNamespaceを作成して、そこにDeployします。

また、マニフェストファイルのディレクトリ構成として、overlays以下をstagingproductionディレクトリに分けて環境差分を切り出しています。
(公式が提供しているExampleのディレクトリ構成を参考に作成しました。)

github.com

GKE(Google Kubernetes Engine)へのDeployに必要な権限については、GCRへのImage pushと同様にService Accountを利用して権限を与えます。
GKEへのDeployの権限を付与する必要があるため、Service AccountにはKubernetes Developer」の権限を付与しておきます。
(権限周りも含めて、下記の記事は参考になりました。)

medium.com

version: 2.1
orbs:
  slack: circleci/slack@3.4.2
jobs:
  deploy_to_staging_cluster:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: apt-get update for wget
          command: |
            apt-get update
            apt-get install -y wget
      - run:
          name: install kubectl
          command: |
            curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
            mv kubectl /usr/local/bin
            chmod +x /usr/local/bin/kubectl
      - run:
          name: install kustomize
          command: |
            wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.4/kustomize_v3.5.4_linux_amd64.tar.gz
            tar xvzf kustomize_v3.5.4_linux_amd64.tar.gz
            mv kustomize /usr/local/bin
            chmod +x /usr/local/bin/kustomize
      - run:
          name: set up google cloud sdk
          command: |
            if [ "${CIRCLE_BRANCH}" == "stg" ]; then
              apt-get install -qq -y gettext
              echo ${ACCT_AUTH} | base64 -d > ${HOME}/account-auth.json
              gcloud auth activate-service-account --key-file=${HOME}/account-auth.json
              gcloud --quiet config set project ${GCP_PROJECT}
              gcloud --quiet config set compute/zone ${CLOUDSDK_COMPUTE_ZONE}
              gcloud --quiet container clusters get-credentials ${GOOGLE_CLUSTER_NAME}    
            fi
      - run:
          name: deploy manifests to gke cluster
          command: |
            kustomize build ./overlays/staging | kubectl apply -n stg -f -
      - slack/status:
          include_project_field: true
          success_message: 'Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          failure_message: 'Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          webhook: ${SLACK_WEBHOOK}
  deploy_to_prodction_cluster:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: apt-get update for wget
          command: |
            apt-get update
            apt-get install -y wget
      - run:
          name: install kubectl
          command: |
            curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
            mv kubectl /usr/local/bin
            chmod +x /usr/local/bin/kubectl
      - run:
          name: install kustomize
          command: |
            wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.4/kustomize_v3.5.4_linux_amd64.tar.gz
            tar xvzf kustomize_v3.5.4_linux_amd64.tar.gz
            mv kustomize /usr/local/bin
            chmod +x /usr/local/bin/kustomize
      - run:
          name: set up google cloud sdk
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              apt-get install -qq -y gettext
              echo ${ACCT_AUTH} | base64 -d > ${HOME}/account-auth.json
              gcloud auth activate-service-account --key-file=${HOME}/account-auth.json
              gcloud --quiet config set project ${GCP_PROJECT}
              gcloud --quiet config set compute/zone ${CLOUDSDK_COMPUTE_ZONE}
              gcloud --quiet container clusters get-credentials ${GOOGLE_CLUSTER_NAME}    
            fi
      - run:
          name: deploy manifests to gke cluster
          command: |
            kustomize build ./overlays/production | kubectl apply -n prd -f -
      - slack/status:
          include_project_field: true
          success_message: 'Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          failure_message: 'Branch: $CIRCLE_BRANCH\nUser:$CIRCLE_USERNAME'
          webhook: ${SLACK_WEBHOOK}
workflows:
  version: 2
  build:
    jobs:
      - deploy_to_prodction_cluster:
          filters:
            branches:
              only: master
      - deploy_to_staging_cluster:
          filters:
            branches:
              only: stg


各環境以下のkustomization.yamlは下記のようになります。
namePrefixの部分は、環境に応じてprd- or stg-となります。
(下記のマニフェストファイルはprd環境のものです)

imagesの部分はkustomize edit set imageコマンドによって書き換えられた内容です。

kubectl.docs.kubernetes.io

patchesStrategicMergeの部分では、環境差分を含んだファイルを指定します。
deployment_patch.yamlの中で、Podのreplica数など環境によって差異がある内容を定義することで、Manifestファイルのbuild時に環境差異を反映したファイルを作成できます。

kubectl.docs.kubernetes.io

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namePrefix: prd-
commonLabels:
  app: test

bases:
- ../../base
patchesStrategicMerge:
- deployment_patch.yaml
images:
- name: gcr.io/sample-cicd-271901/test-go-image
  newTag: <commit_hash>


最終的に環境ごとのNamespaceにGCRにpushされたImageを用いたDeploymentが作成されます。
(下記はStaging環境の検証結果ですが、stg-のPrefixが付いているPod (Deployment) が作成されていることがわかります。)

$ kubectl get pod -n stg 
NAME                            READY   STATUS             RESTARTS   AGE
stg-test-app-7b4bdd896f-2kdrf   1/1     Running   0          13s

$ kubectl describe deployment -n stg 
Name:                   stg-test-app
Namespace:              stg
...
Pod Template:
  Labels:  app=test
  Containers:
   test-app-container:
    Image:        gcr.io/sample-cicd-271901/test-go-image:ad948427c121c88d29854ae4f47e3fde56b8ff17

今後やりたいこと

今回は必要最低限の機能しか実装していないので、追加で下記のような機能を組み込めるといいなと考えています。
(機能追加ができたら、その部分も記事にしようと思います)

  • 脆弱性スキャナー(Trivy?)のCIへの組み込み
  • Conftestを利用したManifestファイルのValidation
  • Open Policy Agentによるポリシーの適用

また、クラスタの作成に関してはTerraformを利用しましたが、その内容に関してもいずれ記事にしようと思います。

mkdocs+GitHub ActionsでMarkdownベースのドキュメントを作成/公開する

はじめに

社内でmkdocsを用いたドキュメント作成を行っていて、markdownベースで書きやすそうと思ったので実際に使ってみることにしました。

この記事では、GitHub Actionsを用いたドキュメントの作成からGitHub pagesでの公開までの自動化も含めて、mkdocsとGitHub Actionsについてまとめています。

mkdocsとは?

MarkdownファイルをHTMLに変換する静的サイトジェネレーターです。
ユーザーはMarkdown形式でサイトの内容を記載した上で、mkdocsコマンドを利用することでドキュメントの作成・確認などを行うことが可能です。

www.mkdocs.org

また、テーマも選択することができるので、好きなデザイン (e.g. Gitbook etc.) を利用したドキュメントを作成することができます。
github.com

GitHub Actionsとは?

ソフトウェア開発で利用できるワークフローの自動化ツール(CI/CDツール)の一つです。
(Travis CI, Circle CIなどの類似サービスと考えていただければいいと思います。)

github.co.jp

ユーザーは.github/workflowsディレクトリ内にワークフローの定義ファイルを作成して配置することで、自動的に実行してくれます。

また、自身で作成したワークフローに定義済みの処理であるActionsを組み込むことも可能です。 今回は下記の2つのActionsを利用します。

  • peaceiris/actions-gh-pages: 静的ファイルのGitHub PagesへのDeploy
  • 8398a7/action-slack: Slackへの通知

github.com
github.com

実装

ワークフローの定義ファイルなどは下記のrepositoryで公開しています。

github.com

自分が定義したワークフローでは、下記のようなフローでドキュメントの公開まで行います。

  1. ユーザーがMaster以外のブランチでDocumentを修正して、Pull Request(PR)を作成する
  2. レビュー後にPRをMaster BranchにMergeして、それをトリガーとしてワークフローのjobが起動する
  3. 静的ファイルからドキュメントのbuildを行う (mkdocs build)
  4. buildしたドキュメントをGitHub Pagesで公開する(peaceiris/actions-gh-pages)
  5. GitHub Actionsの結果をSlackで通知する(8398a7/action-slack)

ドキュメントのテーマはMaterialを利用しました。

squidfunk.github.io

mkdocsの定義

repositoryのdocsディレクトリに作成したドキュメント(Markdownファイル)を配置します。
docsディレクトリの下で作成したフォルダごとにファイルをまとめることも可能です。

docsディレクトリ内のファイルはmkdocs.yml内のnav:の部分で設定します。
タブ機能を有効化しているので、nav:の直下に記載されているHome:などの項目がタブとして表示されています。
さらに、<ドキュメントの名前>:<ドキュメントのファイルパス>の形式で指定して、タブの項目に紐づける形でドキュメントをまとめます。

Hint:の部分のように、階層的にドキュメントをまとめることも可能です。

site_name: taxin-pages
theme:
  name: material
  language: ja
  features:
    - tabs
  palette:
    primary: indigo
    accent: indigo
markdown_extensions:
  - codehilite
  - footnotes
  - meta
  - admonition
  - plantuml_markdown:
      server: http://www.planturl.com/planturl
extra:
  search:
    language: 'ja'
plugins:
  - git-revision-date-localized
nav:
  - Home:
    - Top: index.md
    - Hint:
      - plantUML: about/hint-plantuml.md
    - Build configuration: about/document-build.md
  - Guides:
    - architecture: design/architecture.md


上記の設定でドキュメントの画面は下記のようになります。
Home, Guidesというタブが作成されて、それらのタブに紐付く形でドキュメントがまとめられていることがわかります。
f:id:taxintt:20200607104651p:plain

注意点としてホーム画面としてのindex.mdが必須になるため、index.mdは作成してディレクトリのトップレベルに配置しておきましょう。
index.mdが存在しない場合、ドキュメントのbuild自体が正常に完了しても作成されたドキュメントの表示が崩れることがあります。

www.mkdocs.org

ワークフローの定義

先述した通り、PRのMergeをトリガーとしてワークフローのjobが起動するようにon:の部分で設定しています。
mkdocsなど必要なパッケージをダウンロードして、ドキュメントのbuildとdeployを行います。

buildの際には、--cleanのオプションを指定してbuild時に作成されるsiteディレクトリ配下のファイルを毎回削除してから、ドキュメントをbuildします。
ドキュメントを複数回作成する際に、不要なファイル類が紛れ込まないようにするために必要なオプションとなります。

www.mkdocs.org

name: Deploy mkdocs

on:
  pull_request:
    # masterへのPRをトリガーとして実行する
    branches:
      - master
    types:
      - closed

jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - name: checkout branch 
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: configure git info
        run: |
          git config --global user.name "github-actions-for-deploy"
          git config --global user.email deploy-actions@github.com

      - name: check git status and branch
        run: |
          git status
          git branch

      # mkdocsを利用するためのpython環境のsetupを行う
      - name: setup python env
        uses: actions/setup-python@v1
        with:
          python-version: '3.8'

      - name: install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: mkdocs build
        run: |
           mkdocs build --verbose --clean --strict

      - name: mkdocs deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
           github_token: ${{ secrets.PERSONAL_TOKEN }}
           publish_dir: site
           
      - name: notify slack
        uses: 8398a7/action-slack@v3
        if: always()
        with:
          status: ${{ job.status }}
          fields: repo,message,commit,author,action,eventName,ref,workflow  
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}


GitHub Tokenの設定

ユーザーのSettingsからpersonal access tokenを作成します。
Access Tokenのscopeとしてrepositoryを選択します。

help.github.com

f:id:taxintt:20200607223713p:plain

生成されたTokenの文字列をPERSONAL_TOKENの名前でSecretsとして登録します。

help.github.com

Slackの通知設定

GitHub Actionsの処理結果をSlackに通知するには、Incoming Webhookの設定を行います。
生成されたIncoming WebhookのURLをSLACK_WEBHOOK_URLの名前でSecretsとして登録します。

slack.com

f:id:taxintt:20200607222840p:plain

上記のように、Secrets関連の設定を行えば準備完了です。
あとは、先述の通りにドキュメント作成用のブランチを作成して、MasterブランチにMergeするとドキュメントのBuild+Deployを自動的に行ってくれます。

N予備校(入門webアプリコース)のPostgreSQL環境をdocker-composeで用意した話

はじめに

N予備校PostgreSQL環境をdocker-composeで作ったので記事にしてみました。

私 (@taxin_tt) はSIerでインフラエンジニアとして働いていて、普段コードを書く機会があまりありません。
無料受講キャンペーンをやっていたこともあり、N予備校(入門webアプリコース)でアプリ開発の基本を学び直しています。

www.nnn.ed.nico

自分が受講している入門webアプリコースの中では、サンプルアプリのデータを保存するためにPostgreSQLの環境を用意する必要がありました。

本来はVagrantを使って環境を用意するのですが、めんどくさかったのでDockerの勉強にもなると思い、PostgreSQLの環境をdocker-composeで用意しました。

この記事の執筆時点(5月前半)でもコースは無料で受講でき、利用される方も多いと考え、GitHubで公開することにしました。

作成したもの

github.com

README.mdは英語で記載してありますが、日本語の簡単な説明も下部に記載しています。

使い方

基本的には、git cloneで上記のrepositoryをcloneして、docker-compose upPostgreSQLのコンテナを起動するだけです。
事前にDockerをinstallしておく必要があります。

docs.docker.com

また、docker exec -it <container_name> /bin/bashPostgreSQLのコンテナの中に入ってpsqlでDBの中身などを確認できます。
ユーザー側でDBの作成などの準備を行う必要はありません。

$ docker container ls -a
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                   PORTS                       NAMES
88d645d50d44        postgres:10-alpine     "docker-entrypoint.s…"   26 seconds ago      Up 25 seconds            0.0.0.0:5432->5432/tcp      postgres-container

$ docker exec -it 88d645d50d44 /bin/bash

bash-5.0# su - postgres
88d645d50d44:~$ 
88d645d50d44:~$ psql
psql (10.12)
Type "help" for help.

// 作成したいDB(secret_board)が事前に作成されていることがわかる
postgres=# \l
                                  List of databases
     Name     |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
--------------+----------+----------+------------+------------+-----------------------
 postgres     | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 secret_board | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0    | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
              |          |          |            |            | postgres=CTc/postgres
 template1    | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
              |          |          |            |            | postgres=CTc/postgres
 testdb       | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
(5 rows)


終わりに

簡単に作成した環境ですが、お役に立てば幸いです。
こんな感じの小さめのアウトプットもこまめにブログに載せていこうと思います。

PostgreSQLインスタンスのセットアップが簡単にできるようになったので、これを期にSQLの勉強も始めてみようと思います。 www.postgresql.org

リモートワークのKPTをしてみた

はじめに

本格的にリモートワークに移行して、1ヶ月以上が経ちました。

一人暮らしなので、現時点では仕事にも特に影響もなく過ごすことができています。
最初の内は自宅にまともな作業環境がないところから、必要な物を洗い出して机・椅子・モニター・キーボード etc. を買い揃えたりもしていました。

その一方で、なし崩し的にリモートワークに移行してしまったので、リモートワーク時の生活習慣や仕事の仕方に関しては振り返りができていませんでした。
そこで、直近1ヶ月の振り返りを兼ねて自身のリモートワークに関するKPTを行いました。

KPTとは?

現在取り組んでいる活動の改善を目的として行う振り返り方法の一種です。
Keep (うまくいっていること), Problem (課題・問題点), Try (問題・課題の解決策)を書き出して、現状分析とアクションの明確化につなげます。

studyhacker.net

最初に、上記の項目に関連する内容をひたすら書き出します。

今回はTrelloを利用して、思いついた内容をカードとして作成します。
Trelloには「アクティビティログの編集機能」があるので、その時の考えや感情なども記載しておくことで次回のKPT時の振り返りに利用できます。

f:id:taxintt:20200503152627p:plain

次に、雑多に記載した内容をグルーピングします。
複数人でKPTを行う際には、重複している内容(カード)をまとめる作業もここで行うのがいいと思います。

上記の作業をカードの書き出し(10min) -> カードの整理(5min) と時間を設けて行います。
これをKeep, Problem, Tryの3つの項目ごとに行うと、下記の内容がまとめられているはずです。

  • Keep: うまくいったこと・このまま継続すること
  • Problem: 課題・問題点
  • Try: (KeepとProblemの内容を踏まえて) 新たに実践すること・問題や課題の解決策

KPTをやってみた

GWの1日を利用してKPTを行いました。
一通りKeep/Problemを洗い出した後に、内容をまとめるために下記のようなTopicを設定してグルーピングしました。

  1. 仕事
  2. 身体的な健康 (Physical Health)
  3. 精神的な健康 (Mental Health)
  4. 余暇
  5. その他

下部では実際にKPTの際に挙げた内容の一部を記載しており、Keep/Tryであげた内容の左側にはTopicの番号を振っています。


Keep

  • 業務上のタスクを適切にトラッキングし、期限を超過することなく対応できた (1)
  • 1ヶ月間、運動習慣を継続している(1,2回 / week) (2,3)
  • 継続的に自学自習の時間を設けることができている (2h / day を3週間以上) (1)
  • 自身のキャリアや生活について振り返る時間を設けることができた (3, 5)

Problem

  • 仕事とプライベートの切り替えができていない (1,4)
  • キャンプや登山などアウトドアな趣味が一切できていないのでストレスを感じている (4)
  • タスクに対してかかる時間の想定と実績値にズレがある (1)
  • ダラダラと仕事に取り組む時間が増えている (1)
  • 気分の上下動が激しい (3)
  • 明確に休みの期間を設けて、休みをとっていない (3,4)
  • ワークアウト日以外には一切体を動かしていない (2)
  • 睡眠習慣の乱れがある(PM12時 -> AM1時に睡眠時間がずれこむ) (2)


Try

上記のKeep, Problemの内容を確認した上で、Tryの内容を書き出しました。


1. 仕事のスイッチを入れるためのルーティンワークを設定する

  • 仕事とプライベートの切り替えができていない (1,4)
  • ダラダラと仕事に取り組む時間が増えている (1)

自分は明確に仕事モードに切り替えず、ダラダラと仕事を始めて続けてしまうタイプです。
そのため、業務の開始・終了前後の時間帯は、集中力にムラができてしまうことがあります。

この状況を踏まえて、スイッチのオンオフの変わりとなるルーティンの設定をTryとしました。
ルーティンタスクの候補としては「気持ち的に負担が少なく」「5~10分程度でさくっとできる」という条件で考えてみました。

候補としては、(運動も兼ねた)散歩 or 天気に関係なくできるHeadspaceが挙がっています。
jp.techcrunch.com

Headspaceは瞑想・メンタルヘルスのためのアプリで、音声ガイド付きで最短で1分から、5分・10分といった短い時間帯のレッスンを受けることができます。

HeadspaceはiOS Engineerのmayukoさんの動画で初めて知りました。
(Rebuild.fmのEpisodeでご存知の方は多いかも...?)
www.youtube.com

とりあえずHeadspaceを取り入れて、3分前後の短めのレッスン->仕事という流れをスイッチオンのルーティンにしてみようと思います。


2. アクティブレストを取り入れる

  • ワークアウト日以外には一切体を動かしていない (2)

Problemで挙げたように体を動かす日とそうでない日の差が激しい状態です。
体調的には問題ないので優先度としては低めですが、Problemとして挙げた項目なので、一旦Tryを作成します。 cp.glico.jp

まずはストレッチなど簡単なところから... と思い調べたところ、スマホに入っているNikeのトレーニングアプリの中にYogaのレッスンがありました。
www.nike.com

最初は、2Lessons / weekのペースから始めて、徐々に頻度を上げていこうと思います。
(このあたりは継続的にKPTを行って、設定したペースでできているかを振り返っていきます。)


3. ポモドーロテクニックの導入 ( Trello/Toggl/Strict Workflow )

  • 明確に休みの期間を設けて、休みをとっていない (4)
  • 睡眠習慣の乱れがある(PM12時 → AM1時に睡眠時間がずれこむ) (2)
  • ダラダラと仕事に取り組む時間が増えている (1)

このブログも深夜1時に書いているので改善しないといけないな... と痛感してます。
在宅で仕事をするようになってから、だらだらと作業をしてしまう傾向が顕著になってきたのでTryとしてポモドーロテクニックを導入することを決めました。

www.newsweekjapan.jp

ポモドーロテクニック「25分間の集中作業」と「5分間の休憩」を1サイクルとして繰り返すことで、仕事の効率を上げるテクニックです。
今回は下記の記事を参考に、Trello + Toggl + Strict Workflow(Chrome拡張) を使ってみることにしました。

seleck.cc
普段タスクはTrelloで管理しているのでTrelloとTogglを連携させて、作成したタスクカードからタイマーを起動します。

f:id:taxintt:20200504104521p:plain

同時に、Strict Workflowのポモドーロタイマーを起動します。
タイマーを起動すると、Youtubeなどユーザーが指定したサイトが画面に表示されなくなるので他の誘惑に手を出すことはありません。
(タイマー自体はブラウザの右上に表示されるので、それをチェックしながら作業を行います。)

f:id:taxintt:20200504104647p:plain

タスクが完了したら、Trelloのタスクカードからタイマーをストップします。
Toggl上では自動的にタスクに対してどれだけ時間を使ったかを計測してくれるので、作業時間の見積もりにも使えるかと思います。

f:id:taxintt:20200504105134p:plain

当初は、ポモドーロのサイクル(25分・5分)だと「時間になったら途中でタスクを止めないといけない」と考えてましたが、「最初のサイクルで100%のものを作るのではなく、7,80%の完成度で一旦仕上げて次のサイクルに100%にするように対応する」と考えるようにしています。


4. アウトドア以外の趣味を作る

  • キャンプや登山などアウトドアな趣味が一切できていないのでストレスを感じている (4)

個人的にこのTryが一番難しい...
パッと思いつくのは映画観賞と音楽くらいだったので、最近放置していたNetflixで映画を見るところから始めます。

世の中のアウトドア大好きな人はどう過ごしてるんでしょうね...?
自宅の庭でキャンプとかしてるんでしょうか。


5. ジャーナリングの時間を確保する

  • 気分の上下動が激しい (3)

生活習慣の変化などもあり、気分の上下動が出てしまう状況が続いています。
このProblemに対するTryとして、普通に通勤していた時には、帰宅時の電車内でその日にあったことを思い出しながらジャーナリングをしていました。

www.lifehacker.jp

自分は下記のようなフォーマットで1日の出来事を書き出して、Evernoteにメモしています。

  • 状況: その日に起きたこと(事実ベースで記載)
  • 考え: 状況に対して考えた・感じたこと
  • 感情: その状況に直面した時の感情と程度 (e.g. イライラ(80) etc... )
  • 対応(ToDo): 何かしら対応する必要がある場合のToDo

ストレス要因の明確化や書くこと自体がストレス発散にもなるので継続的に続けていました。
ですが、出勤時間がなくなることで、ジャーナリングの時間も消えてしまっていました。

そのため、夕食時に10分程度時間をとって、ジャーナリングの時間を設けるようにしました。
やること自体は明確になっているので、後は「負担にならない程度の」時間を確保するだけだと思います。

cakes.mu

終わりに

気付いたらリモートワークに移行していたような状況だったので、時間をとってリモートワーク1ヶ月間の振り返りを行いました。

振り返りながら改善を続けていくことで、リモートワークが長期化しても身体的にはもちろん、精神的に健康でいれるように努めていきたいです。

f:id:taxintt:20200504102112p:plain

Kubernetes the hard way (GCP版) #13 (スモークテスト)

Kubernetes the hard way (GCP版)の続きです。

前回の記事はこちら

taxintt.hatenablog.com

Chap13. Smake Test(スモークテスト)

Chap12まででクラスターに関連する設定を一通り行いました。
このチャプターではクラスターが正常に動作しているかを確認するために、一連のタスクを実施します。

一部の作業ログが欠落しているので、手順の内容をそのまま記載している部分もありますがご了承下さい。

github.com

データの暗号化

Kubernetesで利用可能なリソースの一種であるSecretの暗号化機能を確認します。

kubernetes.io

SecretはKubernetesクラスター内で機密情報を管理するためのリソースとして利用されます。
データはControl Plane上のetcdに保管されるので、セキュリティの観点ではetcdの暗号化が必須になります。

qiita.com

最初に、機密情報のKey-Valueのペアを--from-literalで渡して検証用のSecretを作成します。
渡した値は自動的にBase64でencodeされます。

~/w/k/h/04 ❯❯❯ kubectl create secret generic kubernetes-the-hard-way \
  --from-literal="mykey=mydata"
secret/kubernetes-the-hard-way created
~/w/k/h/04 ❯❯❯ k get secrets
NAME                      TYPE                                  DATA   AGE
default-token-bn72d       kubernetes.io/service-account-token   3      178m
kubernetes-the-hard-way   Opaque                                1      14s


Secretの作成後に、Control Planeにログインしてetcd内のデータを確認します。
作成したSecret名を用いてディレクトリ(/registry/secrets/default/kubernetes-the-hard-way)を指定して、Key, Valueを取得します。

github.com

さらに取得したデータをhexdumpコマンドを利用して16進数とASCII文字でダンプします。
etcd上のデータにはk8s:enc:aescbc:v1:key1が付与されており、aescbcプロバイダがキー(key1)のデータを暗号化するために使用されたことを示しています。

kubernetes.io

~/w/k/h/04 ❯❯❯ gcloud compute ssh controller-0 \
  --command "sudo ETCDCTL_API=3 etcdctl get \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/ca.pem \
  --cert=/etc/etcd/kubernetes.pem \
  --key=/etc/etcd/kubernetes-key.pem\
  /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
Enter passphrase for key '/Users/nishikawatakushi/.ssh/google_compute_engine':
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |y.k8s:enc:aescbc|
00000040  3a 76 31 3a 6b 65 79 31  3a 4e ed 61 e8 69 49 fa  |:v1:key1:N.a.iI.|
00000050  19 c2 58 32 f3 7b 5b 7b  f6 2b 67 0e af de a7 0c  |..X2.{[{.+g.....|
00000060  d6 cf 48 b2 e2 7a 2d 44  9d 19 f8 06 8b e8 3d 74  |..H..z-D......=t|
00000070  89 eb 0e ba d4 ec b8 78  0b 84 b0 01 12 83 18 72  |.......x.......r|
00000080  c8 1e a6 25 a7 ca aa c5  a8 3a 0a f4 59 fa 2d 1d  |...%.....:..Y.-.|
00000090  03 54 5b 08 62 c6 5e b1  da 02 1b a6 ab 8f d6 c3  |.T[.b.^.........|
000000a0  ea c6 69 56 53 93 68 b4  29 93 df 21 79 36 1d dd  |..iVS.h.)..!y6..|
000000b0  d3 05 fa fd c5 40 d2 d5  4b e8 c8 da 48 60 3e 6b  |.....@..K...H`>k|
000000c0  29 33 6b 4a 9f f3 1b 8a  02 da 00 45 cd 93 98 ce  |)3kJ.......E....|
000000d0  ac cc d7 a4 a6 93 e0 ae  1d bc 9c 1b 7c e3 c0 ef  |............|...|
000000e0  c9 b6 4e 7a 6f 46 41 12  0e 0a                    |..NzoFA...|
000000ea

Deploymentの作成

次にWorkloadsリソースの1種であるDeploymentを作成します。
kubectl createコマンドを利用することで、マニュフェストファイルを事前に用意することなく作成することが可能です。

$ kubectl create deployment nginx --image=nginx

$ kubectl get pods -l app=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-554b9c67f9-vt5rn   1/1     Running   0          10s

ポートフォワーディング

作成したDeployment(pod)に対して、ポートフォワーディングを行いクラスタ内のコンテナへアクセスします。
今回はnginxのコンテナを作成しているので、コンテナの80番ポートにアクセスします。

~/w/k/h/04 ❯❯❯ POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath="{.items[0].metadata.name}")
~/w/k/h/04 ❯❯❯ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

~/w/k/h/04 ❯❯❯ kubectl port-forward $POD_NAME 8080:80                                                                                                                     
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

~~~~~~~

~ ❯❯❯ curl --head http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Sat, 29 Feb 2020 07:28:01 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 21 Jan 2020 13:36:08 GMT
Connection: keep-alive
ETag: "5e26fe48-264"
Accept-Ranges: bytes


ログ出力

作成したPodに対して、標準出力からPodのログをダンプします。
(この部分は作業ログが無かったため、手順の内容をそのまま記載しています。)

kubernetes.io

手順の中では標準出力の内容を直接取得していますが、実際の運用では標準出力・標準エラー出力をログファイルに書き出してロギング用のAgentを用いて転送したり、sidecarを用いたり様々なケースが考えられます。
こういったロギングの方法については、 Kubernetesの公式ドキュメントにまとめられています。

kubernetes.io

$ kubectl logs $POD_NAME
127.0.0.1 - - [14/Sep/2019:21:10:11 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.52.1" "-"


コンテナ内でのコマンド実行

docker execコマンドと同様に、Kubernetesでも作成したコンテナ上でコマンドを実行することが可能です。
今回はnginxのバージョンを確認するコマンドを実行します。

$ kubectl exec -ti $POD_NAME -- nginx -v
nginx version: nginx/1.17.3


Serviceを用いたアプリケーションの実行

最後に、Serviceを作成してクラスタ外部から作成したコンテナにアクセスできるようにします。
kubectl exposeコマンドを用いて、事前に作成したDeploymentに紐付ける形でServiceを作成します。

kubernetes.io

$ kubectl expose deployment nginx --port 80 --type NodePort

$ NODE_PORT=$(kubectl get svc nginx \
  --output=jsonpath='{range .spec.ports[0]}{.nodePort}')


次に、払い出されたNodePortのポート番号(NODE_PORT)でアクセスできるようにGCPFirewall Ruleでアクセスできるように修正します。

$ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-nginx-service \
  --allow=tcp:${NODE_PORT} \
  --network kubernetes-the-hard-way


最後にNode(GCE)自体のIPアドレスを取得して、curlコマンドを実行します。
正常に設定が行われていれば、ポートフォワーディングの際と同じようなレスポンスが返ってくるはずです。

$ EXTERNAL_IP=$(gcloud compute instances describe worker-0 \
  --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')

$ curl -I http://${EXTERNAL_IP}:${NODE_PORT}
HTTP/1.1 200 OK
Server: nginx/1.17.3
Date: Sat, 14 Sep 2019 21:12:35 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 13 Aug 2019 08:50:00 GMT
Connection: keep-alive
ETag: "5d5279b8-264"
Accept-Ranges: bytes


今回は、Chap13の内容をまとめました。

これにて、Kubernetes the hard wayのブログシリーズは終了です。
(Chap14は作成したリソース類の削除なので、ブログ記事の作成は行いません。)
機会があれば、AWS, Azure版など他のクラウドでのHard wayや手順を一部変更した改造版などを実施してみようと思います。

Kubernetes the hard way (GCP版) #12 (DNSクラスターアドオンのデプロイ)

Kubernetes the hard way (GCP版)の続きです。

前回の記事はこちら

taxintt.hatenablog.com

Chap12. Deploying the DNS Cluster Add-on(DNSクラスターアドオンのデプロイ)

このチャプターでは、サービスディスカバリの役割を果たすクラスターアドオン(CoreDNS)のデプロイを行います。

CoreDNSに関しては、公式ドキュメントにおいてもサービスディスカバリ(=Service Discovery)の一種として紹介されています。

kubernetes.io

(+α)Service Discoveryとは?

その名の通り、特定の条件に該当するサービスを発見するための機能のことを指します。
ただし、ここで記載しているサービスはクラスタ内外のNW疎通を取るために利用されるServiceのことではなく、クラスタ上で動作しているサービスを指しています。

特定のServiceに紐づいているPodを列挙したり、Serviceの名前からServiceのEndpoint(IP)を返すことをService Discoveryと言います。
(ServiceのEndpointに関する処理では、特定のサービスを発見した上でEndpointなど必要な情報を取得しています。)

Service Discoveryに関しては、主に環境変数DNSの2つのモードで実現可能です。

kubernetes.io

DNS Cluster Add-on

今回は、CoreDNSを利用してDNSを用いたService Discoveryを行うためのアドオンを環境にデプロイします。

下記のコマンドを実行して、アドオンとして利用するCoreDNSをデプロイします。

~/w/k/h/04 ❯❯❯ kubectl apply -f https://storage.googleapis.com/kubernetes-the-hard-way/coredns.yaml
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created

~/w/k/h/04 ❯❯❯ kubectl get pods -l k8s-app=kube-dns -n kube-system
NAME                     READY   STATUS    RESTARTS   AGE
coredns-5fb99965-2f569   1/1     Running   0          8s
coredns-5fb99965-4fbr9   1/1     Running   0          8s


applyしたyamlファイル内の設定値は確認できていないですが、おそらく下記と類似したような内容が定義されていると考えられます。
github.com

検証

今回はbusyboxのコンテナをデプロイして、コンテナ内からnslookupコマンドを実行してkubernetesドメイン名からIPアドレスを取得します。
名前解決に成功すると、API Server用に作成されているService(ClusterIP)のクラスターIPが返ってくるはずです。

~/w/k/h/04 ❯❯❯ kubectl run --generator=run-pod/v1 busybox --image=busybox:1.28 --command -- sleep 3600
pod/busybox created
~/w/k/h/04 ❯❯❯ kubectl get pods -l run=busybox
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          5s
~/w/k/h/04 ❯❯❯ POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
~/w/k/h/04 ❯❯❯ echo $POD_NAME
busybox


名前解決を行った結果、API Server用のServiceのクラスターIPを取得することができました。
これにより、クラスタ内での名前解決によるService Discoveryが可能になります。

~/w/k/h/04 ❯❯❯ kubectl exec -ti $POD_NAME -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local


今回は、Chap12の内容をまとめました。

Kubernetes the hard way (GCP版) #11 (Pod用ネットワーク経路のプロビジョニング)

Kubernetes the hard way (GCP版)の続きです。

前回の記事はこちら

taxintt.hatenablog.com

Chap11. Provisioning Pod Network Routes(Pod用ネットワーク経路のプロビジョニング)

このチャプターでは、他のNodeにスケジュールされたPodと通信する際に必要なルーティングの設定を行います。
(ハンズオンの手順も少ないので、今回の記事も比較的短めです。)

ルーティングテーブルについて

最初の説明でも記載しましたが、他のNodeに配置されたPodと通信する際にはルーティングの設定が必要となります。
今回のハンズオンではGCPでネットワーク経路を定義する際に利用するRoutesを用いて設定を行います。

cloud.google.com

最初に、各VMIPアドレスメタデータに設定したCIDRブロックを確認します。

~/w/k/h/04 ❯❯❯ for instance in worker-0 worker-1 worker-2; do
  gcloud compute instances describe ${instance} \
    --format 'value[separator=" "](networkInterfaces[0].networkIP,metadata.items[0].value)'
done
10.240.0.20 10.200.0.0/24
10.240.0.21 10.200.1.0/24
10.240.0.22 10.200.2.0/24

ネットワーク経路について

先ほど確認したIPアドレスとCIDRブロックの情報を基に、ルーティング設定を行います。
設定の際には、下記の項目を指定して引数として渡します。

  • --destination-range: 宛先となるネットワーク(CIDRブロックで定義される)
  • --next-hop-address: 宛先ネットワークに到達するための転送先

この設定によって、--destination-rangeで指定したIPアドレスに対する通信は--next-hop-addressで指定したIPアドレスに転送されます。
これにより、他のNodeにスケジュールされたPodと通信することが可能になります。


~/w/k/h/04 ❯❯❯ for i in 0 1 2; do
  gcloud compute routes create kubernetes-route-10-200-${i}-0-24 \
    --network kubernetes-the-hard-way \
    --next-hop-address 10.240.0.2${i} \
    --destination-range 10.200.${i}.0/24
done
Created [https://www.googleapis.com/compute/v1/projects/k8s-hardway-20200229/global/routes/kubernetes-route-10-200-0-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-0-0-24  kubernetes-the-hard-way  10.200.0.0/24  10.240.0.20  1000
Created [https://www.googleapis.com/compute/v1/projects/k8s-hardway-20200229/global/routes/kubernetes-route-10-200-1-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-1-0-24  kubernetes-the-hard-way  10.200.1.0/24  10.240.0.21  1000
Created [https://www.googleapis.com/compute/v1/projects/k8s-hardway-20200229/global/routes/kubernetes-route-10-200-2-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-2-0-24  kubernetes-the-hard-way  10.200.2.0/24  10.240.0.22  1000


コマンド実行後に、作成したRoutesを確認します。

~/w/k/h/04 ❯❯❯ gcloud compute routes list --filter "network: kubernetes-the-hard-way"
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP                  PRIORITY
default-route-84429476facc48a9  kubernetes-the-hard-way  0.0.0.0/0      default-internet-gateway  1000
default-route-a30ac7a6303348c0  kubernetes-the-hard-way  10.240.0.0/24  kubernetes-the-hard-way   1000
kubernetes-route-10-200-0-0-24  kubernetes-the-hard-way  10.200.0.0/24  10.240.0.20               1000
kubernetes-route-10-200-1-0-24  kubernetes-the-hard-way  10.200.1.0/24  10.240.0.21               1000
kubernetes-route-10-200-2-0-24  kubernetes-the-hard-way  10.200.2.0/24  10.240.0.22               1000

以上で、ルーティングの設定は完了となります。

Kuberneteのネットワークの内部仕様も理解したい方は、NodeにログインしてRouting TableやARP Tableなどを眺めて見るのも面白いと思います。
(自分の環境で検証はできていないですが、PodをDeployすると上記のTableに記載された内容が書き換えられるはずです。)

www.slideshare.net

medium.com

今回は、Chap11の内容をまとめました。

余談ですが、Calicoなどの他のCNI Pluginを用いることでハンズオン自体を改造している人もいるようです。
CNI Pluginに関しては、ネットワーク方式(L3 Native, Overlay(L2 over L3))やNetworkPolicyなど設定内容も異なるので、代表的なPluginを試すのもありかと思います。

qiita.com