GKEにHelmでnginx-ingress, cert-managerを導入しアプリのデプロイ環境を構築するコマンド具体例　

# 初めに

GKE(Google Kubernetes Engine)に[cert-manager](https://github.com/jetstack/cert-manager)で無料SSL証明書を用意し、[nginx-ingress](https://github.com/kubernetes/ingress-nginx)でWEBアプリをドメイン指定にてルーティング表示するデプロイ環境の構築を行いたい。

順に実行すれば構築が完了出来る様に各コマンドラインの具体例を紹介する。

サンプルアプリとしてデフォルトのnginxコンテナを立ち上げ、SSL接続によるWelcome画面の表示をゴールとする。


#前提

* GCPアカウントや対象プロジェクトを作成済み
* コマンドライン環境（gcloudやkubectl）をローカル導入済み
* GCPプロジェクトがコマンドラインから実行可能な状態である（アカウント操作認証済み）
* Helmをローカル環境に導入済み
* 独自ドメインを取得しレジストラの管理画面からDNS設定（Aレコード）が設定可能な状態

#1) GKEクラスタ作成

```bash
% gcloud container clusters create example-cluster --machine-type=g1-small --num-nodes=1 --disk-size 10 --zone asia-northeast1-a
```

#2)nginx-ingress導入

```bash
# 固定IP取得
% gcloud compute addresses create example-cluster-ip --region asia-northeast1

# tillerサービスアカウント
% kubectl create serviceaccount tiller --namespace kube-system

# tillerアカウントにcluster-adminの権限をバインドする（与える）
% kubectl create clusterrolebinding tiller-binding --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
 
# Tiller(helmのサーバサイドのサービス群)をデプロイする
% helm init --upgrade --service-account tiller

# nginx-ingressインストール (controller.publishService.enabled設定でingressが同一IPアドレスを向く)
% helm install stable/nginx-ingress --name nginx-ingress --namespace kube-system --set rbac.create=true --set controller.publishService.enabled=true

# 取得した固定IPを確認
# 独自ドメインのAレコードにも設定
% gcloud compute addresses list | grep example-cluster-ip
 
# 固定IP指定
% kubectl edit svc nginx-ingress-controller --namespace=kube-system
# type: LoadBalancer の直下に下記を追加する
loadBalancerIP: "取得した固定IP"
```
GCP管理画面のGKEのクラスタ、ワークロード、services（各システムオブジェクト含む）のステータスが全てOKで有る事を確認出来たら次へ進む。

#3) depoyment, service, ingressを設定する。

- デフォルトのnginxコンテナを用意
- 
```yaml:nginx-deployment.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  replicas: 3
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 10m
```

```yaml:nginx-service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    name: nginx-service
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: nginx
  type: NodePort
  selector:
    name: nginx
```
- 一旦非SSL版で用意

```yaml:nginx-ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: nginx-ingress
spec:
  rules:
    - host: example.com # 以降、自分で取得したドメインに読み替えて下さい
      http:
        paths:
          - backend:
              serviceName: nginx-service
              servicePort: 80
            path: /
```

```bash
kubectl apply -f nginx-deployment.yml
kubectl apply -f nginx-service.yml
kubectl apply -f nginx-ingress.yml
```

ブラウザで`http://example.com`に接続し非SSL接続でnginx welcome画面が表示される所まで確認する。

#4) cert-manager導入

```bash
# namespace作成
% kubectl create namespace cert-manager
% kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
 
# cert-manager Helm chart
% kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.10/deploy/manifests/00-crds.yaml

# リポジトリ追加     
% helm repo add jetstack https://charts.jetstack.io
% helm repo update
 
# インストール
% helm install --name cert-manager --namespace cert-manager --version v0.10.1 jetstack/cert-manager
```

#5) SSL証明書導入

```yaml:cluster-issuer.yml
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prd
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory # 本番なので失敗時の利用制限に注意
    email: 'yourmail@example.com' # 自分のメアド
    privateKeySecretRef:
      name: letsencrypt-prd
    http01: {}
```

```yaml:certificate.yml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: example-com-tls # 証明書を格納するSecretにつける名前(ドメイン-tls等)
  namespace: default
spec:
  secretName: example-com-tls # 証明書を格納するSecretにつける名前
  issuerRef:
    name: letsencrypt-prd
    kind: ClusterIssuer
  commonName: example.com # ドメイン
  dnsNames:
    - example.com
  acme:
    config:
      - http01:
          ingress: nginx-ingress # 使用しているIngressの名前
        domains:
          - example.com
```

```bash
kubectl apply -f cluster-issuer.yml
kubectl apply -f certificate.yml
```

- 証明書の取得状況を確認

```bash
kubectl describe -f certificate.yml
```

`Certificate issued successfully`などと表示されれば取得完了。

#6) ingressを再設定

- SSL対応版

```yaml:nginx-ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # 要件に応じて任意
  name: nginx-ingress
spec:
  tls:
    - secretName: example-com-tls
      hosts:
        - example.com
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              serviceName: nginx-service
              servicePort: 80
            path: / 
```

```bash
kubectl apply -f nginx-ingress.yml
```

再度ブラウザで`https://example.com`にアクセスしSSL接続でnginxのwelcome画面が表示されている事を確認出来れば成功！

<img width="622" alt=" 2019-11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307773/a8fb17f3-b4d0-eecb-d1f8-679723dbb00d.png">


## 参考

[GKEでなるべく安くKubernetesクラスタを作成してPrometheus + Grafanaを使ってみる Part2]
(https://qiita.com/kter/items/d3b81cc9fd850a934a9e)

[Kubernetesで複数のWebサービスを楽に管理する]
(https://www.yuuniworks.com/blog/2018-06-14-kubernetes%E3%81%A7%E8%A4%87%E6%95%B0%E3%81%AEweb%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E6%A5%BD%E3%81%AB%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B/)

https://hub.helm.sh/charts/jetstack/cert-manager/v0.10.1