6月に幕張で開かれたAWS summitに登壇&ブース出展してきました。
https://aws.amazon.com/jp/summits/tokyo-2019/aws-expo/
https://aws.amazon.com/jp/blogs/startup/summit2019_day1_recap/
EKS導入事例を発表
マツリカでKubernetesがどのように使われ始めているかについて話しました。
スライドは以下のとおりですが、この記事ではもう少しどんな方法を取ったかチョットダケ詳しく書いてみます。
Kubernetesはボトルネック解消のために導入
マツリカの現行システムは創業時の5年ほど前から変更されずに動いています。
そのため、Opsworksによるリソース管理やプロビジョニング、デプロイが行われています。
サーバに対してなにか変更があると、その度にOpsworksからSetupが実行されてじっと待たされることになります。
また、開発者が増えてきたことで開発環境そのものが不足しており、柔軟に環境を増やせる状態にする必要がありました。
※マツリカ特有かもしれない用語を簡単に整理しておきます↓
開発者=アプリケーションエンジニア(Railsエンジニア / React, AngularJSエンジニア他)
基盤=AWS, Kubernetes, CircleCI (インフラ基盤のこと)
Kubernetes + CircleCIによる開発環境PaaS化計画
マツリカではCIツールにCircleCIを採用していました。これを使って、開発者が開発環境を起動出来るようにしてしまおうと考えました。
流れを説明すると次のような構成です。
開発者はソースコードをPushしたあとは、CircleCIのWorkflowを通じて開発環境の起動を承認するだけでよい状態にしています。
実装まで
おおまかに私たち基盤チームが作り込んだのは以下のようなことです。
- AWS上にベースとなるリソースを作成する:Cloudformation
- その上で動作するアプリケーションのコンテナ群を定義したKubernetesテンプレートを作成する
- Pushをトリガーにソースコードを含んだDockerイメージが作成されるようにする:Dockerfile, CircleCI config
- Workflow画面からKubernetesが起動したり削除したりできるようにする:CircleCI config
テストについてはここでは一旦話さないことにします。
Cloudformation
AWS上にベースとなるリソースを作成するための工程です。
VPCに始まりSSHキー、NATGateway、セキュリティグループ、EC2インスタンス定義、RDS定義、ECR定義などを記述したりします。
それとは別に、KubernetesのNodeGroupの設定ファイルも作成しています。
Kubernetesテンプレート
既存のアプリケーションを踏襲した構成になるように、コンテナ群を定義します。
ここでは、DeploymentとServiceで構成しています。
APIコンテナ、Webコンテナ、Redisコンテナ、Mongoコンテナなどを環境変数やリソースLimitと合わせて記述しています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
imagePullSecrets:
- name: dev
containers:
- name: api
image: xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/api:staging
imagePullPolicy: Always
env:
~省略~
resources:
limits:
cpu: 300m
memory: 512Mi
requests:
cpu: 300m
memory: 512Mi
---
kind: Service
apiVersion: v1
metadata:
name: api
spec:
type: NodePort
selector:
app: api
ports:
- name: api
protocol: TCP
port: xxxx
targetPort: xxxx
nodePort: NODEPORT
imagePullPolicyはAlwaysにして、イメージがPushされるたびに新しいイメージをKubernetesがPullしてくるようにしてます。
CircleCI Config
Dockerイメージのタグ付与のためにShell芸をしたり、Kubernetesによる開発環境起動や削除するためのShell芸をしたりします。
Workflowによる制御もするので、ビルド→ECRへPush→Kubernetesで起動 という処理も細々と書いていきます。
CircleCI2.1にすれば、OrbsやExecutorなどが使えるので、多少Configファイルを短くすることが出来るようになっています。
https://blog.vtryo.me/entry/use-circleci-orbs
Orbsを使うのは簡単で、こんな感じで書くと定義されたJobを実行してくれます。
api-build-and-push-image: &api-build-and-push-image
<<: *machine
steps:
- run: *set_GitBranch
- aws-ecr/build-and-push-image:
account-url: AWS_ECR_ACCOUNT_URL
aws-access-key-id: AWS_ACCESS_KEY_ID
aws-secret-access-key: AWS_SECRET_ACCESS_KEY
region: AWS_REGION
dockerfile: kubernetes/api/Dockerfile
repo: api
tag: $GIT_BRANCH
aws-ecr/build-and-push-image:という部分がOrbsです。
https://circleci.com/orbs/registry/orb/circleci/aws-ecr#commands-build-and-push-image
tags:に記述している $GIT_BRANCHは私たちが独自にCircleCIに定義した環境変数です。DockerタグにPushしたブランチ名でタグ付けしてもらいうために設定しています。
なお、その環境変数の定義はrun: *set_GitBranchで実行しています(CircleCIが用意している環境変数以外のものを独自に設定する場合は、$BASH_ENVに読み込ませる必要があります)。
set_GitBranch: &set_GitBranch
description: "CircleCIの環境変数から現在のGitブランチ名を取得し、Dockerイメージタグに設定できるようにスラッシュをアンスコに置換する"
name: set Git Branch
command: |
echo 'export GIT_BRANCH=$(echo $CIRCLE_BRANCH | sed s#/#\_#g)' >> $BASH_ENV
source $BASH_ENV
課題
スライドに書いてある課題以外をこちらに。
- Yaml管理が徐々に大変に
- Configめっちゃながい
KubernetesもCircleCIもYamlですが、どんどん長くなっていってすでに恐怖を感じますね。KubernetesであればKustomizeなどを用いるなどして、今後の運用も考えた方法で管理したいところです。
CircleCIのconfigは現時点では分割することはできないようなので、Orbsを自作するなどの工夫ができればと思います。
もっと詳しく聞きたい人
カジュアルに話を聞きにきてください!