Googleマネージド証明書を使ってGKEをhttps化

# はじめに
前回書いた以下の記事の続きです。
[GitHubActions + ArgoCD + HELMを使ったGitOps手法でGKEへアプリをデプロイ](https://qiita.com/Nishi53454367/items/4a4716dfbeebd70295d1)
引き続き以下を使用するので、詳細はこちらの記事を参照して下さい。

- HELM
- GKE
- ArgoCD

前回はIPアドレス指定で接続していますが、今回は`https://www.hogehoge.com`のFQDNでの接続を仮定しています。

# 追加で必要なもの
- ドメイン・・・この記事ではGoogle Domainsで`hogehoge.com`を購入済みのていで解説します。
- SSL(TLS)証明書・・・Google マネージド証明書を使用します。
- DNS・・・CloudDNSを使用します。

# 1. 静的IPを予約
GCPコンソール上で「VPCネットワーク」→「外部IPアドレス」→「静的アドレスを予約」で静的IPを取得します。
![スクリーンショット 2020-12-27 19.04.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/9cc1f4a8-f27c-4a59-bd4e-077699669087.png)

名前と説明は任意の内容でOK。タイプはグローバルを選択します。
予約名の`www-hogehoge-static-ip`はHELMのカスタムValueに設定するので控えておきます。
予約すると外部IPアドレスが払い出されます。今回は`012.345.678.901`が払い出されたと仮定します。

# 2. CloudDNSへIPアドレスとドメインを設定
GCPコンソール上で「ネットワークサービス」→「Cloud DNS」→「ゾーンを作成」でゾーンを作成します。
![スクリーンショット 2020-12-27 16.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/165a9708-96e4-2dd7-3a6a-fea2ea60ce3e.png)

ゾーン名と説明は任意の内容でOK。DNS名に購入したドメイン(今回は`hogehoge.com`)を入力して作成を行います。
ゾーンの作成が完了したら「レコードセットを追加」を押下してAレコードを追加します。

DNS名に`www`、IPv4アドレスに予約時に払い出された`012.345.678.901`を入力して作成を行います。
![スクリーンショット 2020-12-27 17.04.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/9e9a09d4-0cf1-f2dd-b7c1-6ecedfa0fd03.png)

# 3. DNSにCloudDNSを使用するよう指定
CloudDNSを使用するようにドメイン購入元で設定を行います。これは利用しているサービスによって手順は異なると思います。
今回使用を前提としているGoogle Domainsの場合は以下の公式ページを参考にして下さい。
https://cloud.google.com/dns/docs/update-name-servers?hl=ja

# 4. HELMを修正
Ingressに設定できるSSL(TLS)証明書は以下の通りいくつかあります。
https://cloud.google.com/kubernetes-engine/docs/concepts/ingress?hl=ja#options_for_providing_ssl_certificates
冒頭で記載した通り今回はGoogle マネージド証明書を使用します。
証明書の更新は自動で行ってくれますが、ワイルドカード証明書が使用できません。
このようにメリット・デメリットがあるので、デプロイするサービスの内容や構成によってGoogle マネージド証明書、セルフマネージド証明書どちらを採用するかは検討が必要かと思います。

## Google マネージド証明書のマニフェストを新規作成
ManagedCertificateというCRD(カスタムリソース定義)を使用することで作成できます。

```managedCertificate.yaml
# Google Managed Certificate
apiVersion: networking.gke.io/v1beta2
kind: ManagedCertificate
metadata:
  name: {{ include "..fullname" . }}
spec:
  domains:
    - {{ .Values.domainName }}
```

- apiVersionは、デプロイ先のクラスタバージョンによって異なるので、以下を参考にして下さい。  
  https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs?hl=ja#api_versions
- kindは`ManagedCertificate`固定です。
- metadata.nameはリソース名です。後で設定するので固定でわかりやすい名前を指定してもOKですが、ArgoCD管理画面からデプロイした時に`ArgoCDアプリ名-HELMのChart名`になるようにしています。
- spec.domainsは任意のドメイン名を指定できるように穴埋めにしています。

## Ingressのマニフェストを修正
`helm create`コマンド実行時に作成されたingress.yamlを修正します。

```変更前：ingress.yaml
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "..fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "..labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
## -- ここから下を修正します -- 
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ . }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: {{ $svcPort }}
          {{- end }}
    {{- end }}
  {{- end }}
```

変更後は以下のようになります。
spec下の部分がかなりシンプルになりました。
ワイルドカード証明書が使用できないので修正前のように複数のサブドメインを捌けず、backendに指定するServiceは1つだけです。

```変更後：ingress.yaml
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "..fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "..labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  backend:
    serviceName: {{ $fullName }}
    servicePort: {{ $svcPort }}
{{- end }}
```

## 最後にIngressを使用するカスタムValueファイルを新規追加します

```create-react-app-https-values.yaml
# Pod
replicaCount: 3

# DockerImage
image:
  repository: gcr.io/gitops-react-app/create_react_app
  tag: "3"

# -- ここから下が関係する部分

# service.typeはNodePortを指定
service:
  type: NodePort

# 設定したいドメインを指定
domainName: www.hogehoge.com

# Ingress
ingress:
  # Ingressを有効化
  enabled: true
  annotations:
    # 予約した静的IP名を指定
    kubernetes.io/ingress.global-static-ip-name: www-hogehoge-static-ip
    # ManagedCertificateのリソース名(metadata.name)を指定
    # 「ArgoCDアプリ名-HELMのChart名」になるようmanagedCertificate.yamlを修正済み
    #   ・ArgoCDアプリ名：create-react-app
    #   ・HELMのChart名：web
    networking.gke.io/managed-certificates: create-react-app-web
```

# 5. デプロイ
後はcreate-react-app-https-values.yamlを使用してデプロイすればOKです。
実際にやった時は接続できるようになるまで少し時間がかかったので根気よく待ちます。

# 最後に
- 静的IPをインスタンスに割り当ててないと課金が発生してしまうので、インスタンスを削除した場合など使用していないIPアドレスは解放を忘れずに。
- 完成版のソースは以下です。  
  https://github.com/Nishi53454367/gitops_manifest_helm