アプリケーションのデプロイ

さて、じゃあアプリケーションをデプロイしていきましょう。

## Dockerise

まずはコンテナ化します。
ビルド+マウントの二段構成にし、コンテナイメージはできるだけ小さくします。

行数も少ないのでDockerfile全体を掲載します。

```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ターゲットがありますが、こんな感じです。

```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`に関しては明日触れたいと思います。

では、コンテナイメージをビルドしてみましょう。

```sh
$ 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`のリソースを記述します。

```yaml:app.yaml
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の関係で運用しており、別チームのネームスペースには基本的にアクセスできません。

```yaml:namespace.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: qiita
  labels:
    name: qiita
```

さて、minikube上にデプロイしてみましょう。
......の前に先ほど作成したイメージをDocker Hub上にあげておきます。

```sh
$ docker push kentakudo/qiita-advent-calendar-2019:latest
    ...
latest: digest: sha256:a4bfa8a5177fa0e011d9545c5dfdba64ce0bc3c04dea585ae40e4e3b3aa8f97b size: 949
```

ではデプロイ。

```sh
$ 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サーバーを呼んでみましょう。

```sh
$ 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について書いていこうかなと思います。

[^1]: これは嘘で、直接タスクを依頼することはほとんどないものの、目に見えない形で多くのサポートを受けています。これもまたマイクロサービス体制がうまく行っている証拠ではないでしょうか。