doridoridoriand’s diary

主に技術的なことを書いていく予定(たぶん)

auditlogを出力出来るようにして、promtailでパースしてlokiに送信してみる

現在Kubernetesの証跡ログ(auditlog)周りを業務で扱っており、思ったより情報がなかった(もしかしたら基本なことなので書くまでも無いってこともありますが。。)ので記事にしてみようと思います。 以下寄り証跡ログのことをauditlogとして表現します。

Kubernetesのauditlogはデフォルトでは出力されず、kube-apiserverの起動時にパラメータを追加して起動してあげる必要があります。ここまでは割と事例があるので割愛します。 auditlogの出力ポリシーはGoogle Container-Optimized OSの監査プロファイルを参考に構築すれば大丈夫です。具体的にはconfigure-helper.shスクリプトに書かれているのでこちらを参考にします。

今回はkubernetesをLimaVMで構築し、auditlogを有効化したクラスタの上で作業してみます。クラスタ自体はLimaVMのプリセットで存在する k8s を利用します。VM自体の起動コマンドは以下になります。 VM名は k8s としていますが、それ以外はデフォルト値で上がってきます。CPU: 4コア, メモリ: 4GB, ルートボリューム100GBのVMが出来上がるかと思います

$ limactl start --name=k8s template://k8s

このKubernetesクラスタはkubeadmで構築されており、kube-apiserverのマニフェストなどは /etc/kubernetes/manifests/kube-apiserver.yaml に存在しており、起動時のオプションもここに記述する必要があります。 またauditlogを格納するボリュームのマウント、audit-policy.yamlもconfigとしてマウントしてあげる必要があるため、volumeMountなどの記載も必要になります。
brバニラで起動したkuberenetesクラスタのkube-apiserver.yamlをのdiffは以下のようになります。

diff <(limactl shell k8s-vanilla -- sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml) <(limactl shell k8s -- sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml)
43c43,48
---
>     - --audit-log-path=/var/log/kubernetes-audit/audit.log
>     - --audit-policy-file=/etc/kubernetes/manifests/audit-policy.yaml
>     - --audit-log-maxsize=100
>     - --audit-log-maxbackup=10
>     - --audit-log-maxage=7
93a99,104
>     - mountPath: /etc/kubernetes/manifests/audit-policy.yaml
>       name: audit
>       readOnly: true
>     - mountPath: /var/log/kubernetes-audit
>       name: audit-log
>       readOnly: false
119a131,138
>   - hostPath:
>       path: /etc/kubernetes/manifests/audit-policy.yaml
>       type: File
>     name: audit
>   - hostPath:
>       path: /var/log/kubernetes-audit
>       type: DirectoryOrCreate
>     name: audit-log

設定が問題なければ、kube-apiserver.yamlの保存ととともに、ファイルの変更をkubeletが検知して自動でkube-apiserverが再起動しauditlogを出力する状態になったクラスタが立ち上がります。 設定のどこかに問題があればkube-apiserverが再起動を繰り返すので、kube-apiserverやkubeletのログを確認しましょう。

上記の設定にしていれば、auditlogは /var/log/kubernetes-audit/audit.logに出力されます。中はJSON形式になっており、出力されている量が多ければ100MB毎にローテートされているはずです。 出力されている内容の一部を切り出すと以下の内容になっていました。

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "level": "Metadata",
  "auditID": "b6bf51ff-9ea1-40d8-98bb-a95b2a2ccd21",
  "stage": "ResponseStarted",
  "requestURI": "/api/v1/namespaces/kube-system/configmaps?allowWatchBookmarks=true&fieldSelector=metadata.name%3Dextension-apiserver-authentication&resourceVersion=655053&timeout=8m13s&timeoutSeconds=493&watch=true",
  "verb": "watch",
  "user": {
    "username": "system:kube-scheduler",
    "groups": [
      "system:authenticated"
    ]
  },
  "sourceIPs": [
    "192.168.5.15"
  ],
  "userAgent": "kube-scheduler/v1.26.2 (linux/amd64) kubernetes/fc04e73",
  "objectRef": {
    "resource": "configmaps",
    "namespace": "kube-system",
    "name": "extension-apiserver-authentication",
    "apiVersion": "v1"
  },
  "responseStatus": {
    "metadata": {},
    "code": 200
  },
  "requestReceivedTimestamp": "2023-04-02T03:32:36.682654Z",
  "stageTimestamp": "2023-04-02T03:32:36.685631Z",
  "annotations": {
    "authorization.k8s.io/decision": "allow",
    "authorization.k8s.io/reason": "RBAC: allowed by RoleBinding \"system::extension-apiserver-authentication-reader/kube-system\" of Role \"extension-apiserver-authentication-reader\" to User \"system:kube-scheduler\""
  }
}

これらをPromtailで読み取るためにはscrape_configを作成する必要があります。JSONなのでpipeline_stagesでJSONを利用します。 k=vとなっている要素に対しては以下のように記述し、

- json:
    expressions:
      kind: kind
      apiVersion: apiVersion

要素が更にネストしている場合は再帰的にparseしてあげる必要があるので、sourceで指定して再帰的に読み取るような設定の追加が必要になります。例えば objectRefは要素が {k: {k: v}} のようになっているため、

- json:
    expressions:
    objectRef:
- json:
    expressions:
      resource: resource
      namespace: namespace
      name: name
      apiVersion: apiVersion
    source: objectRef

のような記述が必要となります。 記載が完了し、うまくauditlogをparse出来るようになっていれば、lokiにpromtail経由でlokiにデータが蓄積されるようになっているはずです。 今回はGrafana、Loki、Promtailに関して以下のチャートを利用しました。GrafanaとLokiに関してはLoki-Stackを用いて、Promtailだけは別立てしてLoki-Stackで構築したLokiにデータをpushする形を取っています。

問題なくデータがpushされていれば、GrafanaからデータをExprole出来るようになっているかと思います。Loki-Stackに同梱されているGrafanaを用いると無事表示されているのを確認出来るかと思います。

Promtailのscrape_configも無事Fieldsとして認識しているようです

ローカルに複数のKubernetesクラスタを立てて切り替える

1年以上ぶりの記事投稿。 部署を異動して業務内容が変わり、久しぶりにKuberneresガッツリ触ることになるのでリハビリがてら記事を作成します。同じようなことやっている人は数多居るけれど気にしないスタンスで

Kubernetesをローカルで簡単に構築することができるようになって久しいです。 内容によっては複数の構成の違うKubernetesクラスタを構築してmanifestを適用して挙動の差異をみたいというモチベーションがあるかもしれません。 手元のPCはMacなので、今回はLimaMultipassを利用してクラスタを構築し、それぞれをローカルのkubecltから切り替えて使えるところまでやってみます

Ubuntuの世界に持ち込んで楽をしているのがお分かりかと思いますが気にしてはなりません

やること

  • Limaを用いてクラスタを構築
  • Multipassを用いてクラスタを構築
  • それぞれのkubeconfigをマージ
  • contextを切り替えてそれぞれのクラスタに接続できているかを確認

Limaを用いてクラスタを構築

Limaはテンプレートを食わせてあげてVMを構築することができるのですが、プリセットで豊富なテンプレートが既にあります。 テンプレート一覧は limactl start --list-templates で表示可能です。表示させてあげるとk3sk8sが出てきますので、今回はk8sの方を利用していきます。 起動コマンドは以下の通り。VM名はわかりやすくk8sとしておきました

$ limactl start --name=k8s template://k8s

実行すると以下のウィザードが出てきますので Proceed with the current configuration で構築を進めます。ウィザードが煩わしい、shellscript等で完全自動化したい場合は --tty=false オプションをつけましょう

$ limactl start --name=k8s template://k8s
? Creating an instance "k8s"  [Use arrows to move, type to filter]
> Proceed with the current configuration
  Open an editor to review or modify the current configuration
  Choose another example (docker, podman, archlinux, fedora, ...)
  Exit

構築が進行します。しばらく時間がかかるので待ちましょう。 構築が完了すると、以下の表示がされるのでkubeconfigの場所をメモっておきます(このタイミングで export KUBECONFIG="/Users... 実行しても構いません)

INFO[0459] Message from the instance "k8s":
To run `kubectl` on the host (assumes kubectl is installed), run the following commands:
------
export KUBECONFIG="/Users/doridoridoriand/.lima/k8s/copied-from-guest/kubeconfig.yaml"
kubectl ...
------

Multipassを用いてクラスタを構築

Mutipassは multipass find コマンドで minikubeのテンプレートイメージが既に公開されています。こちらを利用してもよいですし、snapからKubernetesをインストールしてもよいです。 今回はsnapからmicrok8sをインストールして利用してみましょう。以下のようなcloud-initを書いて、cloud-config.yml として保存しましょう

# cloud-config

# resolv.conf
manage_resolv_conf: true
resolv_conf:
  nameservers: ['1.1.1.1']

# package
package_update: true
package_upgrade: true

snap:
  commands:
    00: snap install microk8s --classic
    01: snap install kubectl --classic

runcmd:
  - [ sudo, usermod, -a, -G, microk8s, ubuntu ]
  - [ /snap/bin/microk8s.enable, dns, dashboard, metric-server ]

以下コマンドで構築します。Limaで構築したスペックと合わせてメモリ4GB、CPU4コアとしました

$ multipass launch --cpus 4 --disk 100 --mem 4GB --name k8s --cloud-init cloud-config.yml;

構築が完了すると Launched: k8s と表示されます。表示されたら以下コマンドでkubeconfigを取得します。 Limaと違いボリュームマッピングしてないのでローカルに保存されず、VMにコマンドを実行して取得する必要があります

$ multipass exec k8s -- /snap/bin/microk8s config view

それぞれのkubeconfigをマージ

$KUBECONFIG変数を用いるパターン、--kubeconfigオプションを用いるパターンなどがありますが、少々面倒なので2つのkubeconfigをマージしてしまいましょう。 kubeconfigの要素を抜き出すと以下のようになります

apiVersion: v1
clusters:
- cluster:
  ...
contexts:
- context:
  ...
current-context:
kind: Config
preferences: {}
users:
- name: admin
  ...

ここで clusterscontextsusersがリスト型になっているので、それぞれのクラスタで作成したkubeconfigを並べて書いてあげればよさそうです

apiVersion: v1
clusters:
- cluster:
  ...
- cluster:
  ...
contexts:
- context:
  ...
- context:
  ...
current-context:
kind: Config
preferences: {}
users:
- name: admin
  ...
- name: admin
  ...

実際に挙動を見てましょう。分かりやすさと操作性の向上の観点から kubectx コマンドを利用しています

$ kubectx
kubernetes-admin@kubernetes
microk8s

無事2つ表示されました。今は上の kubernetes-admin@kubernetes が選択されている状態です。kubectlコマンドを実行してnodeの差異を見てみましょう

$ kubectl get nodes
NAME       STATUS   ROLES           AGE   VERSION
lima-k8s   Ready    control-plane   20h   v1.26.2

Lima側のnodeが表示されました。次にcontextを切り替えてMultipass側のクラスタを見てみましょう

$ kubectx microk8s
Switched to context "microk8s"

$ kubectl get nodes
NAME   STATUS   ROLES    AGE     VERSION
k8s    Ready    <none>   3h12m   v1.26.1

Multipass側のnodeが表示されました。これでローカルで複数のクラスタを構築し、切り替えて利用できるようになりました。 ローカルのマシンパワーの問題はありますが、サクッと構築できるので諸々検証が捗りますね

GUIのUbuntuを手っ取り早く用意する方法

開発の関係でササッとGUIが使えるLinux環境を用意する必要があり、忘備録がてらブログに起こしました。Macで実行しましたが、Windowsでも問題なく実行できると思います。 事前にMutipassをインストールしておいてください。
※1年以上ぶりの更新になってしまいました。。あっという間過ぎて草

とても簡単で、このフォーラムに書いてあることを実施すればOKです。

  • ubuntu-desktopmとxrdpをインストールする
  • ubuntuユーザーにパスワード追加
  • Remote Desktopクライアントから接続

cloud-init.yml経由でubuntuを初期設定していること、ubuntuユーザー以外で実行したかったことから、cloud-config.ymlを用意して実施しました。

# package
package_update: true
package_upgrade: true
packages:
  - ubuntu-desktop # enable GUI
  - xrdp # connect via RDP

users:
  - name: ユーザー名
    groups: admin
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash

chpasswd:
  list: |
    ユーザー名:パスワード
  expire: False

以上のファイルを cloud-config.yml として保存し、Multipassでの起動時にオプションとして渡してあげます。

  • CPU4コア
  • メモリ6GB
  • ディスク128GB
  • マシン名ubuntu-desktop

として作成します。

$ multipass launch --cpus 4 --disk 128GB --mem 6GB --name ubuntu-desktop --cloud-init cloud-config.yml

ubuntu-desktopのインストールにかなり時間が掛かりMultipassがタイムアウトのエラーを吐きますが、裏で順調にインストールが続いているのでそのまま待ちます。 作ったVMにログインし、psコマンドなどを使ってインストールプロセスの有無を確認しても良いかもしれません。

作成後、Multipassのlistコマンドを利用して、払い出されているIPを確認します。このIPはマシン内部でのみ有効です。

$ multipass list
Name                    State             IPv4             Image
ubuntu-desktop                 Running           192.168.64.9     Ubuntu 20.04 LTS

Remote Desktopクライアントをホストにインストールし、接続してみます。Microsoft公式のクライアントが一番良いのでAppStoreからインストールします。

f:id:doridoridoriand:20210712214713p:plain
+マークから Add PC を選択し、先程取得したIPアドレスPC name: に入力し、Add ボタン押下でPCを追加します。

f:id:doridoridoriand:20210712215049p:plain
PCリストに表示されたら、早速接続してみます。

f:id:doridoridoriand:20210712215402p:plain
リモートサーバーの証明書が検証できなかったエラーが出ますが、問題ないので connect を押下します。

f:id:doridoridoriand:20210712215635p:plain
先程cloud-init経由で作成したユーザ名とパスワードを入力し、 continue を押下します。

f:id:doridoridoriand:20210712215950j:plain
設定が問題なく済んでいれば、無事Ubuntuのデスクトップが表示されるはずです。

Docker Buildxを利用してマルチアーキテクチャなdockerコンテナを作成する

classmethod 若槻さんの記事 Dockerのマルチアーキテクチャイメージについて調べてみた を読んでマルチアーキテクチャなdockerコンテナを作ってみたくなったので、忘備録として記事を書きます。

ビルドの方法が分からなかったので、dockerの公式サイトを覗くと記載がありました。 Leverage multi-CPU architecture support

Docker Official Imagesの githubリポジトリ を覗くと、対応しているアーキテクチャは2020年4月12日時点で

  • ARMv5 32bit (arm32v5) ※非公式
  • ARMv6 32bit (arm32v6)
  • ARMv7 32bit (arm32v7)
  • ARMv8 64bit (arm32v8)
  • Linux86-64 (amd64)
  • Windows x86-64 (windows-amd64)
  • IBM POWER8 (ppc64le) ※非公式
  • IBM z Systems (s390x) ※非公式
  • x86/i686 (i386) ※非公式

とのようです。(i386Linuxのみかな)

AWSが提供しているa1インスタンスのcpuinfoを見てみると

$ cat /proc/cpuinfo
processor   : 0
BogoMIPS    : 166.66
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd08
CPU revision    : 3

と表示されました。ARMのドキュメントを検索すると次のページがヒットしました
ARM Information Center

このページ書かれている内容から、

CPU implementer  : 0x41 => ARM Limited.
CPU part    : 0xd08 => Cortex-A72 processor.

ということが分かりました。Cortex-A72はARMv8アーキテクチャを採用しているCPUなので、問題なくマルチアーキテクチャビルドのコンテナが動くはずです。検証環境が整うことがわかったので今回は、

  1. マルチアーキテクチャのdockerコンテナをビルド
  2. docker hubにpush
  3. 手元のPCとARMインスタンスのEC2にpullしてきて動かす

を実施してみようと思います。

前準備

exprimental featureの有効化

マルチアーキテクチャのコンテナビルドのためには experimental feature(試験的な機能)を有効にする必要があります。Docker Desktopでは、

f:id:doridoridoriand:20200412203715p:plain
Docker Desktop

のように config.json を記載するエリアがあるので、 Use the Docker command line | Docker Documentation に記載されているJSONを入力します。

もしくは、ホームディレクトリ直下の .docker ディレクトリに config.json があるので、同様の内容を記載すればおkです(Linuxでも同じです)。

buildKitのインストール

今回使用する buildx というプラグインMoby BuildKit の拡張であるため、BuildKitのインストールが必要になります。 Macであれば

$ brew install buildkit

でもいいですし、公式に則った形でバイナリを /usr/local/bin 配下に設置してもいいでしょう。 buildctl コマンドが通ればインストール完了です。

$ buildctl
NAME:
   buildctl - build utility

USAGE:
   buildctl [global options] command [command options] [arguments...]

VERSION:
   v0.7.0

COMMANDS:
   du        disk usage
   prune     clean up build cache
   build, b  build
   debug     debug utilities
   help, h   Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug                enable debug output in logs
   --addr value           buildkitd address (default: "unix:///run/buildkit/buildkitd.sock")
   --tlsservername value  buildkitd server name for certificate validation
   --tlscacert value      CA certificate for validation
   --tlscert value        client certificate
   --tlskey value         client key
   --tlsdir value         directory containing CA certificate, client certificate, and client key
   --timeout value        timeout backend connection after value seconds (default: 5)
   --help, -h             show help
   --version, -v          print the version

buildxプラグインの追加

次に buildx というプラグインが必要になるので、 リポジトリ から最新のバイナリをダウンロードします。 ホームディレクトリにある .docker ディレクトリに cli-plugins というディレクトリを作成し、先程ダウンロードしたバイナリ docker-buildx という名前で保存します。

更に実行権限を付与します。

$ chmod a+x ~/.docker/cli-plugins/docker-buildx

以上が終わって、docker buildx コマンドが通れば利用可能です。

$ docker buildx

Usage:  docker buildx COMMAND

Build with BuildKit

Management Commands:
  imagetools  Commands to work on images in registry

Commands:
  bake        Build from a file
  build       Start a build
  create      Create a new builder instance
  inspect     Inspect current builder instance
  ls          List builder instances
  rm          Remove a builder instance
  stop        Stop builder instance
  use         Set the current builder instance
  version     Show buildx version information

Run 'docker buildx COMMAND --help' for more information on a command.

ビルド

今回は、rubyで実行したら実行マシンの現在時間を出力するコンテナを利用します。Dockerfileは以下の内容を利用します。

FROM ruby:2.6.3

CMD ruby -e "puts Time.now"

普通にビルド&実行をしてみると

$ docker build -t multi-arch-norm -f multi_arch_Dockerfile .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM ruby:2.6.3
 ---> d529acb9f124
Step 2/2 : CMD ruby -e "puts Time.now"
 ---> Running in f6ca4f8d0f5b
Removing intermediate container f6ca4f8d0f5b
 ---> 7a130a088630
Successfully built 7a130a088630
Successfully tagged multi-arch-norm:latest

$ docker run -it --rm multi-arch-norm
2020-04-12 12:15:34 +0000

と問題なく実行出来ること分かりました。

ではマルチアーキテクチャモードでビルドを実行してみます。

docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t doridoridoriand/multi-arch:latest . 
multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")

どうやら現在の docker driver ではマルチアーキテクチャのコンテナをビルドできないようです。指示に書いてあるとおり、 docker buildx create --use を実行します。

$ docker buildx create --use
$ ecstatic_roentgen

ランダムな名前でビルド用のコンテナが作成されました。

$ docker ps
CONTAINER ID        IMAGE                           COMMAND             CREATED             STATUS              PORTS               NAMES
8ce5fa2759e8        moby/buildkit:buildx-stable-1   "buildkitd"         6 minutes ago       Up 6 minutes                            buildx_buildkit_ecstatic_roentgen0

確かにbuildkitのコンテナが起動していることが分かります。

再度ビルドコマンドを実行します。

$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t doridoridoriand/multi-arch:latest .
WARN[0000] No output specified for docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
[+] Building 133.1s (9/9) FINISHED
 => [internal] booting buildkit                                                                                                                                                                                                          7.3s
 => => pulling image moby/buildkit:buildx-stable-1                                                                                                                                                                                       6.5s
 => => creating container buildx_buildkit_ecstatic_roentgen0                                                                                                                                                                             0.7s
 => [internal] load .dockerignore                                                                                                                                                                                                        0.0s
 => => transferring context: 2B                                                                                                                                                                                                          0.0s
 => [internal] load build definition from Dockerfile

出力が長いので省略

無事ビルドができたようです。ただ、WARNには、

No output specified for docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

と書かれていることから、コンテナのビルド結果はキャッシュにしか残ってないようです。利用するには --push オプションでdocker hubにpushするか、--load オプションでローカルに持ってくるかが必要になるようです。今回は後で別マシンでpullしたいので、docker hubにpushすることにしました。

pushオプションを付けて再度実行したところ、無事にpushされ、単一のイメージタグで、複数のCPUアーキテクチャが利用出来るようになっています。

f:id:doridoridoriand:20200412223844p:plain
無事マルチアーキテクチャになっている

以下が実際にpushしたdocker imageになります。 multi-arch | Tags

pull&実行

実際に動くか試します。まずはx86-64(amd64)PCで実施します。cpuinfoは

processor       : 5
vendor_id       : GenuineIntel
cpu family      : 6
model           : 158
model name      : Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz

長いので省略

となっています。コンテナをpullして実行してみます。

$ docker pull doridoridoriand/multi-arch:latest
$ docker run -it --rm doridoridoriand/multi-arch:latest
2020-04-12 13:54:31 +0000

無事動きました。

次にARM(arm32v8)マシンで実施します。cpuinfoは

$ cat /proc/cpuinfo
processor       : 0
BogoMIPS        : 166.66
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

となっています。コンテナをpullして実行してみます。

$ sudo docker pull doridoridoriand/multi-arch:latest
$ sudo docker run -it --rm doridoridoriand/multi-arch:latest
2020-04-12 14:06:47 +0000

無事実行できました。

まとめ

Dockerがマルチアーキテクチャをサポートしたことで、IntelAMDのCPU以外でもDockerコンテナを動かす敷居が低くなりました。AWSで言えば、c系インスタンスとa系インスタンスのハイブリット構成でAPIサーバーを構築することも不可能ではなくなったので、実際に採用するかは別として、アーキテクティングの幅が広がったかと思います。

機会があれば、ミドルウェア等で試してみようと思います。

SREと私と時々障害

これは SRE Advent Calendar 2019 25日目の記事です。
世の中はクリスマスですね。特に意識していなくても浮足立ってしまうのは、まだ子供なせいなのでしょうか。
タイトルの付け方が何となく一昔前な気がするかもしれませんが、これしか思いつかなかったのと、結構気に入っているのでこのままでいきます。

注意: この記事はポエムが含まれております

現在とSREになるまでの変遷

現在私はとあるメディアサービスを提供している会社のSREチームでエンジニアとして働いています。所属しているチームは、

  • インフラエンジニア(私): 1人
  • バックエンドエンジニア: 3人

計4人で構成されています。

ここでSREチームに所属するまでの、私の変遷をご紹介したいと思います。

  • 2016年6月~12月 バックエンドエンジニアとして新卒で現在の部署に配属。とあるメッセンジャーアプリのAPIの開発 + Webフロントエンドの開発に従事。
  • 2017年3月より、インフラ局に所属。インフラエンジニアに転向し、先輩とともにインフラ業務に従事。12月に先輩が退職し、1人体制となる。
  • 2018年1月から、バックエンドエンジニアとしてインフラ業務に従事。
  • 2018年10月SREチーム発足。現在に至る。

元々バックエンドエンジニアでしたので、複数のLLを業務レベルで書くことは可能でした。私をインフラに誘ってくれた先輩は以下の理由によりインフラにも向いていそうだなと思ったようです。

  • 内定者時代からAWSの経験があった
  • サーバーのスペックに敏感だった
  • IDEVSCodeを使わず、ターミナルで開発していた(コンソールのVimで開発してました)

インフラも面白そうだなと思っていたので、そこまで迷うこともなく(コーディングから離れることに対する一抹の不安はありましたが)転向をお願いしました。 それから10ヶ月程度、現在の稼働サービスのインフラの状況から、運用に必要な実務レベルでのインフラ知識などを教えていただきました。

ここで転機となったのはその先輩の退職です。

  • サービス規模、ユーザー数拡大に負荷増大や、それに伴う既存の設計の問題の露呈
  • 老朽化に伴う移行作業
  • 最新技術等の導入
  • 障害対応業務

バックエンドエンジニアと協力して作業するのはもちろんですが、インフラ視点からのアドバイスをできるのが1人になってしまいました。
またインフラサイドにおける細かな運用業務も基本的には1人になりました。

今までのやり方をそのままやるのでは潰れてしまうので、私はできる限り自動化・容易化することに注力しました。ここでバックエンドエンジニアの力が活きてきました。
改善業務の一部として以下を行いました。

半年くらいをかけて、大小様々ですが100個程度のスクリプトを作成しました。このスクリプト達のおかげで、1人でもなんとかなるところまで持ってこられました。

SREの発足

次に転機となったのはSREチームの発足です。Googleが2017年の1月にSRE本のテキストを無料公開し、業界的にも徐々にSREに関して注目が高まっている頃でした。

2018年10月頃、開発責任者からSREチームの発足を告げられます。この時私はSREとしてうまく稼働できるかに関してはあまり自信がなく、現状のインフラ+αになる程度ではと思ってました。 これに関しては、SREと活動している現在も、私のミッションは主にインフラ+αなのですが、結果的に問題ないのではと思っています(※後述します)

バックエンドチームから切り離され、SREチームとなったメンバーは手探りで自分たちのミッションを決めていく必要がありました。そこでまずは本家に従おうということで、SRE本のチームでの輪読会を開きます。 ここから現在の開発組織における問題と対応策をみんなで話し合いました。

GoogleがO'Reillyから出版している「Site Reliability Engineering」は非常にボリュームがあり、また全部を輪読してもただの読書会になることが目に見えていたので、重要なところをかいつまみ、担当を割り振って実施しました。

一通りSREとしての先行事例を知ることができたので、次は自分たちの事業部に当てはめる作業になります。あくまでもGoogleの事例は、

「世界的に利用されているサービスを、複数の国と地域にまたがった開発組織を利用して、継続的かつ安定的なサービス運用する」

ために必要な仕組み等が多分に含まれています。

Googleのサービス群に比べれば小規模であり、ほとんどのサービス利用者が国内である、日本向けのサービスを展開している現在の事業部にそのまま当てはめるのは現実的ではありません。 また、SREチームは新規技術の開発というミッションも負っていたので、この時点で通常のSREチーム同様の働きはできなくなりました。

まずはじめにチームとして以下の内容に関して取り組むことになりました。

  • SLI/SLOを定義
  • 属人化している障害対応をもっと開発チーム全体で満遍なくできるようにする
  • 負荷試験の継続的な実施のための整備
  • ログ周りの整備可視化の充実化
  • トイルの継続的な改善・解消

SLI/SLOを定義に関しては私のミッションの1つだったので、実施背景を説明します。
この時すでにSREという単語が世間的にもある種のバズワードになっており、それに付随する単語も、聞いたことはあるが、具体的にどのようなもの分かっていないという状況だったと思われます。 そこでまずはSREとは何か、何のために存在するのか、目的は何なのかをはっきりさせるため、事業部のエンジニア全員が集まる開発定例にて勉強会を実施し、単語の定義及びミッションの共有の必要があると考え、実施しました。
なお、開発状況及び私自身のミッションの変更などにより、現在は別の担当者に引き継がれております。

状況の変化

現在の事業部の開発はビジネスに寄り添った開発スタイルを採っています。よって開発項目もビジネスの方向性の変更などにより俊敏に変更する必要があります。これ自体はとても素晴らしいことだと思っているので問題は無いのですが、SREチームのメンバーがSRE業務ではなく新規機能開発の方に比重を置かなくてはいけない時間が多くなりました。

またSREチームあるあるなのかもしれませんが、使用ミドルウェアのアップデートなど、定常的なインフラ業務が減っておらず、またインフラエンジニアが私だったこともあり、SREチームというよりは、バックエンドチームの新規機能開発チーム+インフラというような状況になっていました。

私自身も別のサービスのインフラを担当するなど、現在所属している事業部にとどまらず、現在出向している子会社のインフラを全般的に見るようになってきて、別チームと仕事をすることも増えてきました。

現在とこれから

現在はSREチームはKubernetesを利用したマイクロサービス基盤の開発・運用チームとなっております。現在EC2上で動いているアプリケーションも徐々にこのマイクロサービス基盤に移行されていく予定とのことです。
アプリケーションの移行に関しても、インフラエンジニアがメインで関わることなく、 バックエンドエンジニアが主体となって進められる状況を生み出せたことはとても良かったと考えております。

私は現在以下のミッションを実施しております

  • カオスエンジニアリングの導入・実施
  • 視聴品質の定常的な計測・可視化
  • 旧型インフラの改廃
  • 他サービスのインフラ・バックエンドエンジニア

インフラ半分SREのようなもの半分といったところでしょうか。
〇〇エンジニアといったロールが元々好きでは無いので(専門性は別にロールが無くても増やすことは出来ると考えているので)、個人的には望ましい状況になってきております。

SREというチームが必要なのではなく、SREの思想を少しでもバックエンドエンジニアが持っていることのほうがとても重要なので、以上のミッションを通して、バックエンドエンジニアにSREの思想及びその根底にあるインフラの知見を布教できればと考えております。


障害の話一度もしませんでしたね。。笑
正直なところ、ここには書けないので面識ある方はランチや飲みなどに誘ってください。話せる範囲で話します笑

AnsibleでKubernetes開発に必要なツールをインストールする

小ネタです。 Kubernetes開発用の作業用サーバーを構築する時に書いたので、何となく書いてみます。 EC2ならユーザーデータとかでやればええやんとかいう正論は受け付けません

一応理由を説明すると、

  • 起動時に毎回インストール作業が実行されるのがあまりよろしくない
  • インストールされているか否かをチェックするスクリプトを書き始めたら、そもそもユーザーデーターの責務では無い気がした(ユーザーデーターに記述されている内容は、起動時に毎回実行されるべきなはず)
  • 様々な資産があり、慣れているAnsibleで書いたほうが良いのでは?

という理由によるものです

インストール内容

作業サーバー(ツール群をインストールする対象のサーバー)のOSはAmazonLinux2を利用しています。今回は以下のツールをインストールしました

最近のツールはバイナリを放り込めば完成するパターンのものが多いので、インストールが楽になりました。 これらツールも例に漏れずバイナリ(もしくは単体のスクリプト)を放り込めばインストールが完了します

できたもの

早速結果を貼っちゃいます

kubectl

kubectx

kubens

eksctl

get_urlunarchive が素晴らしいので特筆すべきことは無いのですが、全てバージョン等を指定せず、Ansible実行時の最新を持ってくるように書いています。冪等性をあえて乱すような書き方をしていますが、Kubernetes界隈は開発が活発なので、常に新しいものを使うのが正義であると考え、この形にしています

Kubernetesの作業用サーバーを用意するといった考え方がもう古いような気もしますが、忘備録的にまとめてみました

クラウドベンダーのIPアドレス範囲の調べ方

小ネタです。クラウドベンダーがIPアドレスをどのくらい保有しているのか気になって調査したことがあったので、記事に起こしてみました。

今回調べたクラウドベンダー

今回はIPv4のみ調査しました。IPv6を含めると マンドクセ 膨大になりすぎて後述するスクリプトの計算が終わらないので。

AWS

AWSでは保有しているIPアドレスのCIDRブロックをAPIとして 公開 しています。 ページに記載されているCIDRブロックを計算すればIPアドレス保有数がわかります。 以下のようなコードを書いて個数を調べてみました

※計算時間短縮のため、並列演算をしています。実行するとCPUを使い切る挙動になるのでご注意ください。

試しに実行したところ、

$ ruby show_number_of_aws_ip_address.rb
I, [2019-09-28T20:25:00.222308 #61863]  INFO -- : Start to parse IP Address ranges of AWS.
I, [2019-09-28T20:25:00.786106 #61863]  INFO -- : Number of CIDR blocks: 1818
I, [2019-09-28T20:34:05.882460 #61863]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of AWS: 93482928

9300万個所有しているようです。多いですね。

GCP

GCPではspfレコードに所有しているIPアドレス一覧を 記載 しています。 シェルで試しに引っ張ってきてみました。

$ netBlockAddr=(`dig -t txt _spf.google.com +short | tr ':' '\n' | grep net | tr ' ' '\n' | grep net`); for i in ${netBlockAddr[@]}; do dig -t txt $i +short; done | tr ' ' '\n' | grep ip4 | tr ':' '\n' | grep -v ip4;
35.190.247.0/24
64.233.160.0/19
66.102.0.0/20
66.249.80.0/20
72.14.192.0/18
74.125.0.0/16
108.177.8.0/21
173.194.0.0/16
209.85.128.0/17
216.58.192.0/19
216.239.32.0/19
172.217.0.0/19
172.217.32.0/20
172.217.128.0/19
172.217.160.0/20
172.217.192.0/19
108.177.96.0/19
35.191.0.0/16
130.211.0.0/22

※shell力がうんこなので、どなたかもっと良い書き方あったら教えて下さい(切実)

AWSの時と同様にスクリプトを書いてみました。

$ ruby show_number_of_gcp_ip_address.rb
I, [2019-09-28T21:15:23.028779 #91774]  INFO -- : Start to parse IP Address ranges of GCP.
I, [2019-09-28T21:15:23.678997 #91774]  INFO -- : Number of CIDR blocks: 19
I, [2019-09-28T21:15:25.140817 #91774]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of GCP: 322816

めちゃくちゃ少ない。。!
本当に合っているのか不安になる少なさですね。GoogleAppEngineに関してはこのリストに入ってない可能性もあるので、もうちょっと調べてみます(多分)

Azure

Azureでは、以前はXMLによるファイル提供での公開だったのですが、その手法が 廃止予定 になり、その代わりとして Service Tag DiscoveryAPI がプレビュー公開されています。今回はService Tag DiscoveryAPIを利用した方法で計算してみます。

以下のスクリプトで調査可能です。

$ ruby show_number_of_azure_json_ip_address.rb
I, [2019-09-28T21:27:09.594383 #96119]  INFO -- : Start to parse IP Address ranges of Azure.
I, [2019-09-28T21:27:10.568397 #96119]  INFO -- : Number of CIDR blocks: 17009
I, [2019-09-28T21:29:32.258446 #96119]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of Azure: 30981085

特筆すべきはCIDRブロックの多さですね。比較的細かいアドレスレンジを大量に集めているようです。


クラウドベンダーのアドレスをブロックしたいニッチな要求(このご時世実施したらメリットよりデメリットのほうが大きいと思いますが)の時などに参考になればと思います。
IBM CloudやOracle Cloud Platformも、時間を見つけて追加していこうと思います。