さて、じゃあアプリケーションをデプロイしていきましょう。
Dockerise
まずはコンテナ化します。
ビルド+マウントの二段構成にし、コンテナイメージはできるだけ小さくします。
行数も少ないのでDockerfile全体を掲載します。
FROM golang:1-alpine AS build
RUN apk update && apk add make git gcc musl-dev
ARG SERVICE
ADD . /tmp/${SERVICE}
WORKDIR /tmp/${SERVICE}
RUN make clean install
RUN make ${SERVICE}
RUN mv ${SERVICE} /${SERVICE}
FROM alpine:3.9
ARG SERVICE
ENV APP=${SERVICE}
RUN apk add --no-cache ca-certificates && mkdir /app
COPY --from=build /${SERVICE} /app/${SERVICE}
ENTRYPOINT /app/${APP}
バイナリ名はSERVICE
という名前でビルド時に変数として与えます。
また、clean、installとバイナリのmakeターゲットがありますが、こんな感じです。
SERVICE := qiita-advent-calendar-2019
GIT_HASH := $(shell git rev-parse HEAD)
LINKFLAGS := -X main.gitHash=$(GIT_HASH)
.PHONY: install
install:
go get -v ./...
$(SERVICE):
go build -ldflags '$(LINKFLAGS)' .
.PHONY: clean
clean:
@rm -f $(SERVICE)
Makefile
に関しては明日触れたいと思います。
では、コンテナイメージをビルドしてみましょう。
$ docker build -t kentakudo/qiita-advent-calendar-2019 --build-arg SERVICE=qiita-advent-calendar-2019 .
...
Successfully built ed7e36125fc2
Successfully tagged kentakudo/qiita-advent-calendar-2019:latest
$ docker images | grep qiita-advent-calendar-2019
kentakudo/qiita-advent-calendar-2019 latest ed7e36125fc2 32 seconds ago 14MB
Kubernetesマニフェストファイル
実際にはマニフェストファイルは別レポジトリで管理しています。が、今回はアプリケーションのレポジトリ内に置いてしまいます。
特に変わったところはなく、シンプルにService
とDeployment
のリソースを記述します。
apiVersion: v1
kind: Service
metadata:
name: &app qiita-advent-calendar-2019
namespace: &ns qiita
labels:
app: *app
spec:
ports:
- name: srv
protocol: TCP
port: 8080
selector:
app: *app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: &app qiita-advent-calendar-2019
namespace: &ns qiita
spec:
replicas: 1
selector:
matchLabels:
app: *app
template:
metadata:
namespace: *ns
labels:
app: *app
spec:
containers:
- name: *app
image: kentakudo/qiita-advent-calendar-2019:latest
env:
- name: SRV_PORT
value: "8080"
ports:
- containerPort: 8080
name: srv
Service
ではhttpサーバを走らせる8080ポートを開放しています。
こちらはネームスペースのマニフェストファイル。チームとネームスペースは1:nの関係で運用しており、別チームのネームスペースには基本的にアクセスできません。
kind: Namespace
apiVersion: v1
metadata:
name: qiita
labels:
name: qiita
さて、minikube上にデプロイしてみましょう。
......の前に先ほど作成したイメージをDocker Hub上にあげておきます。
$ docker push kentakudo/qiita-advent-calendar-2019:latest
...
latest: digest: sha256:a4bfa8a5177fa0e011d9545c5dfdba64ce0bc3c04dea585ae40e4e3b3aa8f97b size: 949
ではデプロイ。
$ kubectl --context=minikube apply -f kubernetes/namespace.yaml
namespace/qiita created
$ kubectl --context=minikube apply -f kubernetes/app.yaml
service/qiita-advent-calendar-2019 unchanged
deployment.apps/qiita-advent-calendar-2019 created
$ kubectl --context=minikube -n qiita get pods
NAME READY STATUS RESTARTS AGE
qiita-advent-calendar-2019-7c885c5698-hwkts 1/1 Running 0 6m42s
うまくいっているようです。
ポートフォワードしてhttpサーバーを呼んでみましょう。
$ kubectl --context=minikube -n qiita port-forward qiita-advent-calendar-2019-7c885c5698-hwkts 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
$ curl localhost:8080/bar
Hello, world
いい感じですね。
僕はアプリケーションのエンジニアなので正直クラスタアドミン的なことは全くわかりません。それでもインフラチームの助けをほとんど借りることなく1サービスの運用ができています。マイクロサービスでのチーム開発のポテンシャルを発揮していていいなーと実感するところです。
明日はMakefileとCIについて書いていこうかなと思います。
-
これは嘘で、直接タスクを依頼することはほとんどないものの、目に見えない形で多くのサポートを受けています。これもまたマイクロサービス体制がうまく行っている証拠ではないでしょうか。 ↩