taxin's notes

読書、勉強メモ etc.

転職して一ヶ月経った

tl; dr

色々やっています。
Kubernetesは引き続き細々とやっていきます。
コード書く機会を増やしていきたい。

何やってるの?

8月に転職して某社でSREとして働いています。
転職の経緯などはこちらに記載しているので、よろしければどうぞ。

taxintt.hatenablog.com

今はDatadog使って監視周りの改善活動をしたり、SLI/SLOの導入のためにDesign Docsをベースにチーム用のガイドラインを書いたりしてます。
Monitoring, Logging, Alertingの改善やインフラ更改のお手伝いなど、やることはたくさんありますが楽しく過ごしています。

コードはほとんど書いていません。(もとからそんなに書いてなかったので書く量としてはそんなに変わっていないです。)
Cloud Functionsを触った時に少しGoを書いたり、Pythonを書いたりしたくらいです。

最近やったこと

8月末にCKAを取りました。(Score: 86%)
内容が9月から変わるとのことで、勉強内容自体はあまり参考にならないかもしれないので単体で記事にするのはやめました。

training.linuxfoundation.org

試験対策として、Hard wayを復習したりUdemyのCKAのコースを一通りやったりしました。
Udemyのコースは、Static PodやKubernetes NetworkingのベースとなっているNetwork Namespaceなどが初見の内容も多く、まだまだ知らないことがあるなあ...となった記憶があります。

www.udemy.com

これからやりたいこと

CKAの勉強もひと段落したので、9月以降は隙間時間でコードを書いてきたいと考えています。

理由としては2つあって、一つは技術的な課題に対してコードを書いて簡単なツールが作っていれば「痒いところに手が届く」ケースが増えたこと、もう一つはスキル的に伸び悩みを感じている今の状態から脱却するための足掛かりにしたいという理由です。

ゴリラさんの「プログラミング上達のコツ」をたまたま拝見したり、参加するMeetupの中でインフラエンジニアがコードを書くことに関する話が出てたりする中で、今年の残りはコーディングに力を入れようと思いました。
docs.google.com

インフラに関連する部分で小さなツールをGoで作り始めるところから始めていきたいです。
(なんとなくアイデアはあるので、それを形にするところから...)

最後に

何とか生き残れるように頑張りますので、これからもよろしくお願いします。

退職エントリ

TL; DR

2020年の7月末をもって、3年と4ヶ月勤めたSIerを退職しました。

誰?

@taxin_tt という名前でTwitterやったり、blog書いたりしています。
k8s初心者向けのMeetupであるKubernetes Meetup Noviceの運営もやっています。(運営メンバー募集中ですので興味あればお声がけ下さい。)

github.com

speakerdeck.com

自身の振り返りも兼ねて、この記事を書いています。

どんなことしてた?

退職する直前までは、AWSのインフラ運用とコンテナ環境で利用するセキュリティツールの機能検証を行っていました。
AWSとセキュリティ(コンテナ + 認証・認可) に比重を置いて仕事をしてきたと思います。

それ以前は、色々な仕事・勉強会に携わらせていただきました。

  • コンテナ環境におけるセキュリティに関する勉強会 + 社内セミナーの講師
  • 自社サービスを用いた業務フロー改善のPoC
  • 自社製品の導入サポート etc.


なぜ退職したの?

一言で言うと、自分が取り組みたいことと会社内で求められることの間にギャップがあり、それを埋めていくことが難しいと判断したからです。

取り組みたい技術分野への(案件)アサインや業務における技術的な部分とマネージメントの比率などいくつかギャップを感じる部分があり、最終的に社外で自身の希望を満たす仕事を求めることにしました。

会社自体にネガティブな印象を持つかもしれませんが、尊敬できる人も多く、(少なくとも自分の観測範囲では)非常に良い環境だと思っています。


どんなことやるの?

とある会社のSREチームに入ります。(具体的に何をやってるかはいずれまとめる予定です。)
前職ではチームの作業区分の影響でインフラの一部のみ見てきましたが、新しいところでは一通り全て見ることになりそうです。

DB, キャッシュ周りは個人的にちゃんと勉強したいです。(というか何も知らないので基礎知識は身に付けたい)


その他

その他と言いつつ、書いてみたらこっちの方が分量が多くなってしまいました。

特に記事にしてはいなかったのですが、4月からUoPeopleのComputer Scienceコースに入学していました。
継続して学習を続けることができればCSの学士号(Bachlor)を取得することができます。

www.uopeople.edu

文系出身ということもあり、Computer Scienceの基礎知識が足りないことに対する不安を常に持っていました。
自学自習でカバーすることも考えたのですが、体系的なCS分野の学習+英語学習の両方ができると考え最終的にApplyすることを決めました。
(下記の記事などを参考に、最終的には「やってみて違ったら別の方法に切り替えればいいでしょ」くらいの気持ちで決めた気がします。)

tmkk.hatenablog.com

snamiki1212.com

転職活動との掛け持ちに関してですが、正直その時は掛け持ちできませんでした。
4月下旬~5月下旬は転職活動もピークになり、加えて仕事とプライベートの問題に挟まれて折り合いがつかなくなり、最終的にAdvisorと相談してCourseをDropしてお休みしていました。
(TwitterでUoPeopleの課題のこと呟かなくなったな、こいつ...」と思われた方もいるかもしれません。)

次のTerm1 (First dayは9/3) からCourseは再開するつもりです。
その頃には仕事の要領も掴んで、業務とCourseを両立できるようになっているでしょう。(多分)

www.uopeople.edu

これからも学習は続けていきたいと思います。

最後に

KubernetesのWorkspaceに流れてきたSlackメッセージに反応してなければ、社外の人と関わりを持つこともなく、自身のキャリアについて考えてこの年次での退職を決断することもなかったと思います。
(今振り返ると、この集まりに参加して本当によかったなと実感しています。)

f:id:taxintt:20200527000533p:plain

こんな感じで、チャンスがあれば手を出してみる(動いてみる)ことを意識して引き続きやっていきます。
皆様、これからもよろしくお願いします。

個人目標の振り返り(2020年上半期)

はじめに

7月も半月近く経過してしまったので、今年の上半期振り返り記事を書いてみようと思います。
仕事関連のものは含めず、個人的に実施したものを中心に「何をやろうと計画して」「どこまでやったか」を振り返りました


上半期の目標と振り返り

上半期は、やりたいこと・興味のあることをいくつかの分野に分けて目標設定を行いました。
分野はざっくりと下記のように分けました。(AWSなど仕事で触っているものは下記の分野からは外しています。)

  • インフラ周りの基礎 (OS, NW etc.)
  • コンテナ / Kubernetes
  • IaC (主にTerraform)
  • アウトプット
  • コーディング
  • Private

目標をDaily or Weekly or Monthlyのタスクに落とし込んだものに関しては、目標の左側に設定したタスクの実行頻度を記載しています。
一部、1月〜3月で実施したものもありますが、4月〜6月で実施した内容がメインとなります。


インフラ周りの基礎 (OS, NW etc.)

インフラ基礎の学習: 1.5冊 / 3冊 (Not Yet)

4月〜6月までで、下記の3冊を課題図書としました。
一番上の本のみ読み終えて、2つ目の「ITインフラの仕組み」については現在も読み進めています。

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

上半期を振り返って、最も改善が必要な部分は「本・Blog記事をベースとしたインプット」だと考えています。
アウトプットをメインに据えた目標設定をしていたこともありますが、それを差し引いても上半期のインプットの量は想定より少なかったです。

原因に関しては、ざっと下記のようなことが挙げられるかと思います。

  1. 技術書を読み進めるスピードが単純に遅い
  2. (本の内容が) 単なる文字列としてしか頭に入ってこない現象が度々あった
  3. インプットした本の内容とそれをベースにした考察・検証を「どこにどのように」まとめるかが決めていない

2.に関しては、単なる集中力の問題かなとも思いつつ、解決策が見つからなくてもやもやしていたのですが、リーディングトラッカーの存在を最近知ったので下半期はこれを利用してみます。


(1.に関しては、2の現象によって読み進めるのを止めたりした部分もあるので、リーディングトラッカーでどの程度改善できているかを見ていきたいと思います。)

また、3.に関しては、Hackmdにまとめつつ、はてなBlogに小さめの粒度で内容をまとめようかなと計画しています。
(負担にならない程度の小さめのアウトプットによって記録を残し、インプットによる知識を定着させることができればベストです。)

コンテナ / Kubernetes

Kubernetes The Hard Wayの完走 + Blog記事作成 (Done)

Kubernetes The Hard Wayを完走し、全Chapterの解説記事を作成しました。
(下記のChapter1の記事からChapter13までの解説記事をBlogに書きました)
taxintt.hatenablog.com

自分が運営として携わっているKubernetes Meetup Noviceの運営メンバーで集まって1日かけて実施しました。
また、完走後に勉強した内容を記事でまとめる宣言もしていたので、最後のChapterまで記事を書き切れてよかったです


Kubernetes完全ガイド読了 + 各リソースの検証: 5P / 日 (Not Yet)

当初はCKAを7月前半に受験する想定で、上記の学習を実施してました。
6月中は継続的に時間を取ることが難しかったことから、CKAの受験時期をずらしたので学習も一時的に中断していました。
(中断前までで7割程度読み終えていて、現在は学習再開しています。)

完全ガイドを読み終わったら、試験対策としてUdemyと下記の問題集を一周する予定です。
www.udemy.com

github.com

(バウチャーの有効期限もあるので)CKAの試験内容は変わるより前の8月の初旬~中旬にCKAを受験する予定です。


余談ですが、Kubernetes完全ガイドの第二版が発売されることを知りました。
(第一版を読了する前に第二版が発売されることのないように、早めに読み進めなければ...)

books.rakuten.co.jp


CI/CD Pipelineの「プロトタイプ」作成 (Done)

Kubernetes環境を前提としたCI/CD Pipelineに興味があったので自分で作ってみました。
GCRへのイメージプッシュからGKEへのデプロイまでの基本機能をCircleCIとKustomizeを用いて実装しました。
taxintt.hatenablog.com

基本的な機能の実装にとどまっているので、このプロトタイプをベースに修正・追加の実装を行っていく予定です。

IaC (主にTerraform)

Pragmatic Terraform on AWSの写経: ? P/日 (Done)

上記は、1月〜3月で実施したタスクの内の一つです。
(何ページずつ進めていたかは失念しましたが、4,5P/日くらいで進めていた記憶があります。)

booth.pm


一通り、写経してみてTerraform(HCLの書き方も含めて)に慣れたのは大きいと思います。
実際の業務では、単純に書くだけではなくディレクトリ構成・環境差分への対応方法・tfstateの分割など実運用を意識した設計や実装をする必要があると思うので、そういった観点での学習もできればいいかなと思います。


アウトプット

Blog記事の執筆: 記事2~3本 / 月 (Done)

上半期だけで、20本 (振り返り記事も含めて)の記事を作成していました。
どのような記事を書いたかに関しては割愛しますが、コンテナ・Kubernetes関連の記事が7割くらいを占めていたと思います。

(20記事程度書いて、450アクセスいかないくらいでした。)
f:id:taxintt:20200715212938p:plain


(社内/社外の両方で) 勉強会・Meetupでの登壇

上半期は人前で話す機会に恵まれました。
社内向けには、NIST SP800-190をベースにしたコンテナセキュリティの概論についてセミナーをしました。 (社内向けのセミナーなので、スライドは非公開です。ご了承ください。)

社外向けには、Kubernetes Novice Tokyo(#1)で、EKS 101というタイトルでLTをしました。
speakerdeck.com


コーディング

コーディングに関しては、春頃から時間を確保して色々やっていました。
(AtCoderに関してもやっていましたが、他のタスクを優先して現在は気が向いたらABCに参加するくらいです。)

N予備校(プログラミング入門 Webアプリコース) : 2レッスン/日 (Done)

アプリケーションの実装における基礎を一通り頭に入れるために上記のコースをやりました。
単にコードを書くだけではなく、API設計やデータモデリングの部分も説明されていたので、設計面を踏まえた上で実装のレッスンに移れるという点で非常にありがたかったです。
www.nnn.ed.nico

VMベースでの環境構築に耐えかねてDockerを用いてPostgreSQLのDB環境構築を行った際には、その内容もブログ記事として書いたりしました。
taxintt.hatenablog.com

Learn-go-with-tests : 1レッスン/日 (Not Yet)

現在は、Goの学習のために、TDDをベースとしたこのテキストを使ってコードを書いています。
andmorefine.gitbook.io

もともと、Pythonをメインで書いていて動的型付け言語しかまともに書けない状態だったので、静的型付け言語で且つとっつきやすそうなGo言語を勉強しています。
(KubernetesとGoの相性が良いこともあり、何かしら応用できるのではないかという部分もモチベーションの一つになっています。)


Private

ランニング: 1回 / 週 (Done?)

上記に関しては、大体目標達成することができました。
(厳密に言うと1,2月は一回ずつ足りないかもしれません)

  • 1月: 19.88km / 4 Runs
  • 2月: 33.97km / 4 Runs
  • 3月: 35.26km / 5 Runs
  • 4月: 52.20km / 8 Runs
  • 5月: 52.85km / 7 Runs
  • 6月: 58.35km / 9 Runs
  • 上半期Total: 252.52km / 37 Runs

雨と引越しなどでバタバタしていたこともあり、最近は家の周りをウォーキングするにとどまっています。
(前回のRunから2週間近くも間が空いてしまっています。早く梅雨が空けて欲しい...)


英会話: 2回 / 週 (Not Yet)

コロナの影響で校舎が閉鎖してしまったこともあり、目標は未達成となってしまいました。
(対面式のスクールに通っているので、ここはどうしようもない部分ではありますが...)

英語で話す機会を増やしたことで、英語を話す際は多少は口が慣れてきました。
その一方で、会話時に語彙・文法の貧弱さが出ているので、下半期はこの部分のインプットが必須になってくると思います。


下半期の目標

下半期に関しては全体的にインプットの比率を高めて、同時にインプットの質の改善にも取り組んでいきます。
目標設定と日々のタスクへの落とし込みは実施中なのですが、現段階で下記は実施予定です。
(下半期の目標設定の話はまた別記事で書こうと思います。)

インプット(分野全般)


コンテナ / Kubernetes

  • CKA / CKADの取得
  • TerraformでのGKEハンズオンの作成


アウトプット

  • 1, 2記事 / 月の頻度でのブログ記事の作成


コーディング

  • (Golang) client-goを用いたサンプルクライアント or TUIツールの実装


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