GKEへのRancher 2.1の導入手順


# 目的

地味にGKE(Google Kubernetes Engine)にRancher 2.x系統のインストールではまる部分があるので解説します。

# 前提

- Cloud DNSを使って操作可能なドメインを保有していること
- Helmの基本的な操作ができること

# 手順概要

1. Helmの導入
2. external-dnsの導入
3. nginx-ingressの導入
4. cert-managerの導入
5. Rancher 2.1のインストール

# 手順詳細

## Helmの導入

ここでは、`helm`コマンドの導入については解説せず、
GKE上で稼働するk8sクラスタに`tiller`を導入する手順について解説します。

`tiller`を動作させるためのサービスアカウント`tiller`を準備します。
`tiller`サービスアカウントには、`cluster-admin`クラスタロールを付与します。

```yaml:rbac-config.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
```

```bash:サービスアカウントの作成とtillerの導入
$ kubectl apply -f rbac-config.yaml
$ helm init --service-account tiller
```

## external-dnsの導入

### external-dnsサービスアカウントの作成

`external-dns`で利用するためのサービスアカウントをGCP上に作成します。

`IAMと管理`メニューを選択肢、`サービスアカウント`をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/fd17980f-9822-02a1-69df-39a653ea1943.png)


`+サービスアカウントを作成`リンクをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/4ae48e75-5302-0e32-62a6-8311435513d4.png)


`サービスアカウント名`に`external-dns`を指定して、`作成`ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/7589f38f-6bbb-09f9-5630-858e26a1fc4a.png)


`external-dns`サービスアカウントに`DNS管理者`権限を付与します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/891f3e86-eefe-0dbf-5c82-3857fcd12ae2.png)
`続行`ボタンをクリックして作業を進めます。

`キーの作成`ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/8d2a2f10-ef6a-9293-1ff6-cc34f6746a17.png)


`JSON`を選択し、`作成`ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/283eaa43-7ded-f518-ff55-9ffd7b530ea4.png)

ここでjsonファイルのダウンロードが始まるのでこれを保存します。
(ここで保存したファイルを`credentials.json`とします)

### external-dnsサービスアカウントの認証情報をk8sクラスタに登録

先程ダウンロードした`credentials.json`をbase64エンコーディングします。
(下記コマンドはUbuntu 18.04の場合です。OSごとにコマンドが異なるので注意してください)

```bash:credentials.jsonのbase64エンコーディング
$ cat credentials.json | base64
hogehoge
```
`secret-external-dns`Secretリソースを作成します。
`data`のキーとして`credentials.json`、値として先程のbase64エンコーディングの結果を記述します。

```yaml:secre-external-dns.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-external-dns
type: Opaque
data:
  credentials.json: "hogehoge"
```

ここで作成した認証情報を登録するための`external-dns` namespaceを作成します。

```bash:external-dns名前空間の作成
$ kubectl create namespace external-dns
namespace/external-dns created
```

`external-dns`namespaceに`secret-external-dns.yaml`の内容を適用します。

```bash:external-dnsサービスアカウントの認証情報のk8sクラスタへの登録
$ kubectl apply -f secret-external-dns.yaml -n external-dns
```

### external-dnsの導入

まず、操作対象となるk8sクラスタの所属するプロジェクトのIDを確認します。
一般的には、GKEのk8sクラスタが所属しているGCPプロジェクトを選択します。
(下の例の場合だと`samplegoogle-project`となります)

```bash:projectの確認
$ gcloud projects list
PROJECT_ID             NAME               PROJECT_NUMBER
samplegoogle-project   SampleProject      2312869999999
```

```bash:external-dnsのインストール
$ helm install stable/external-dns \
    --set provider=google\
    --set google.project=samplegoogle-project\
    --set google.ServiceAccountSecret=secret-external-dns \
    --set rbac.create=true \
    --set rbac.serviceAccountName=external-dns \
    --set rbac.apiVersion=v1 \
    --name external-dns \
    --namespace external-dns
```

DNSサービス(`Cloud DNS`)のプロバイダがGoogleなので、`provider`に`google`、
今回対象としているGCPプロジェクトのIDが`samplegoogle-project`なので、
`google.project`に`samplegoogle-project`、
Cloud DNSを操作するためのサービスアカウントの認証情報を`secret-external-dns`リソースに入れているため、
`google.ServiceAccountSecret`に`secret-external-dns`を指定します。
また、今回GCPに作成したサービスアカウント名が`external-dns`であるため、
`rbac.serviceAccountName`に`external-dns`を指定します。

また、`external-dns`namespaceにインストールするため、
`--namespace external-dns`を指定します

### external-dnsのインストール後確認

```bash:Podの起動の確認
$ kubectl get pods -n external-dns
NAME                           READY   STATUS    RESTARTS   AGE
external-dns-f8bd984f4-c6jhn   1/1     Running   0          3m
```

```bash
$ kubectl logs pod/external-dns-f8bd984f4-c6jhn -n external-dns
time="2018-11-14T13:06:42Z" level=info msg="config: {Master: KubeConfig: RequestTimeout:30s IstioIngressGateway:istio-system/istio-ingressgateway Sources:[service ingress] Namespace: AnnotationFilter: FQDNTemplate: CombineFQDNAndAnnotation:false Compatibility: PublishInternal:false PublishHostIP:false ConnectorSourceServer:localhost:8080 Provider:google GoogleProject:youtubecaption-206603 DomainFilter:[] ZoneIDFilter:[] AlibabaCloudConfigFile:/etc/kubernetes/alibaba-cloud.json AlibabaCloudZoneType: AWSZoneType: AWSAssumeRole: AWSMaxChangeCount:4000 AWSEvaluateTargetHealth:true AzureConfigFile:/etc/kubernetes/azure.json AzureResourceGroup: CloudflareProxied:false InfobloxGridHost: InfobloxWapiPort:443 InfobloxWapiUsername:admin InfobloxWapiPassword: InfobloxWapiVersion:2.3.1 InfobloxSSLVerify:true DynCustomerName: DynUsername: DynPassword: DynMinTTLSeconds:0 OCIConfigFile:/etc/kubernetes/oci.yaml InMemoryZones:[] PDNSServer:http://localhost:8081 PDNSAPIKey: PDNSTLSEnabled:false TLSCA: TLSClientCert: TLSClientCertKey: Policy:upsert-only Registry:txt TXTOwnerID:default TXTPrefix: Interval:1m0s Once:false DryRun:false LogFormat:text MetricsAddress::7979 LogLevel:info TXTCacheInterval:0s ExoscaleEndpoint:https://api.exoscale.ch/dns ExoscaleAPIKey: ExoscaleAPISecret: CRDSourceAPIVersion:externaldns.k8s.io/v1alpha CRDSourceKind:DNSEndpoint ServiceTypeFilter:[]}"
time="2018-11-14T13:06:42Z" level=info msg="Created Kubernetes client https://10.19.240.1:443"
time="2018-11-14T13:06:44Z" level=info msg="All records are already up to date"
```

`external-dns`のPodが起動していることがPodのログとして`All records are already up to date`などの
メッセージがあれば正常に動作していると判断して良いでしょう。

## nginx-ingressの導入

Nginx ingressの導入に際しては以下の部分についての注意が必要です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/71e76d9a-e30c-d487-8b67-57a2b129413a.png)
https://rancher.com/docs/rancher/v2.x/en/installation/ha/
より引用

この図にあるように、Nginx ingress controllerの前にL4のロードバランサーが必要です。
L4のロードバランサーの利用には、GCPでは静的IPアドレスの取得が必要となるので、この取得とNginx Ingress Controllerの導入手順を解説します。

### 静的IPアドレスの取得

`VPCネットワーク`メニューを選択したあと`外部IPアドレス`をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/c8d75ae9-d1ec-b0e1-c558-d74a85ab17f3.png)

`静的IPアドレスを予約`リンクをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/106f6a10-0109-d906-0107-8b8e830497aa.png)

`名前`に`rancher`を指定します。
更にリージョンとして今回k8sクラスタを立ち上げている`asia-northeast1`を指定します。
ここまで設定が完了したら、`予約`ボタンをクリックします

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/c5721a5f-519b-f83d-83e0-3a71a4a1e413.png)

静的IPアドレスが外部アドレスとして割り当てられていることを確認します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/8bb2649e-bf87-8ebd-4d36-bb990d9936a9.png)

ここで取得したIPアドレスを仮に`8.8.8.8`と今後の手順では仮置きして解説します。

### nginx-ingressのインストール

```bash:nginx-ingressのインストール
$ helm install stable/nginx-ingress \
    --set rbac.create=true \
    --set controller.publishService.enabled=true \
    --set controller.service.loadBalancerIP=8.8.8.8 \
    --name nginx-ingress \
    --namespace nginx-ingress
```

｀--set controller.service.loadBalancerIP=8.8.8.8｀のIPアドレス部分には、
先程の作業で取得したIPアドレスを指定します。

```bash:podの起動確認
$ kubectl get pods -n nginx-ingress
NAME                                             READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-6cb58b9bbb-n6wrc        1/1     Running   0          1m
nginx-ingress-default-backend-544cfb69fc-4tvsc   1/1     Running   0          1m
```

```bash:controlPodのログ確認
$ kubectl -n nginx-ingress logs nginx-ingress-controller-6cb58b9bbb-n6wrc
-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:    0.19.0
  Build:      git-05025d6
  Repository: https://github.com/kubernetes/ingress-nginx.git
-------------------------------------------------------------------------------

I1114 13:15:57.456172       6 flags.go:184] Watching for Ingress class: nginx
nginx version: nginx/1.15.3
W1114 13:15:57.464280       6 client_config.go:552] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I1114 13:15:57.464731       6 main.go:191] Creating API client for https://10.19.240.1:443
I1114 13:15:57.477090       6 main.go:235] Running in Kubernetes cluster version v1.11+ (v1.11.2-gke.18) - git (clean) commit 5796233393d7bc034428de15191ad3d2eaff95fb - platform linux/amd64
I1114 13:15:57.479610       6 main.go:100] Validated nginx-ingress/nginx-ingress-default-backend as the default backend.
I1114 13:15:57.987832       6 nginx.go:256] Starting NGINX Ingress controller
I1114 13:15:58.014568       6 event.go:221] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"nginx-ingress", Name:"nginx-ingress-controller", UID:"5dd77f27-e80f-11e8-93be-42010a9201cf", APIVersion:"v1", ResourceVersion:"34850", FieldPath:""}): type:'Normal' reason: 'CREATE' ConfigMap nginx-ingress/nginx-ingress-controller
I1114 13:15:59.188916       6 nginx.go:277] Starting NGINX process
I1114 13:15:59.190894       6 leaderelection.go:185] attempting to acquire leader lease  nginx-ingress/ingress-controller-leader-nginx...
I1114 13:15:59.192361       6 controller.go:171] Configuration changes detected, backend reload required.
I1114 13:15:59.198787       6 leaderelection.go:194] successfully acquired lease nginx-ingress/ingress-controller-leader-nginx
I1114 13:15:59.199190       6 status.go:197] new leader elected: nginx-ingress-controller-6cb58b9bbb-n6wrc
I1114 13:15:59.431225       6 controller.go:187] Backend successfully reloaded.
I1114 13:15:59.432060       6 controller.go:197] Initial synchronization of the NGINX configuration.
I1114 13:16:00.434350       6 controller.go:204] Dynamic reconfiguration succeeded.
```

`Dynamic reconfiguration succeeded.`のメッセージが出ていれば問題なし。

## cert-managerの導入

Helmのチャートからインストールするだけなので、手順のみを掲載します。

```bash:cert-managerの導入
$ helm install stable/cert-manager \
    --namespace cert-manager \
    --name cert-manager
```

```bash
$ kubectl -n cert-manager get pods
NAME                            READY   STATUS    RESTARTS   AGE
cert-manager-787d565b77-4l4k8   1/1     Running   0          52s
```

```bash
$ kubectl -n cert-manager logs cert-manager-787d565b77-4l4k8
I1114 13:20:24.108042       1 start.go:79] starting cert-manager v0.5.0 (revision 7924346bd84e41053cc508956b0a1b567c932416)
I1114 13:20:24.122455       1 controller.go:126] Using the following nameservers for DNS01 checks: [10.19.240.10:53]
I1114 13:20:24.123793       1 leaderelection.go:175] attempting to acquire leader lease  cert-manager/cert-manager-controller...
I1114 13:20:24.124610       1 server.go:84] Listening on http://0.0.0.0:9402
I1114 13:20:24.140288       1 leaderelection.go:184] successfully acquired lease cert-manager/cert-manager-controller
I1114 13:20:24.145318       1 controller.go:68] Starting issuers controller
I1114 13:20:24.145702       1 controller.go:68] Starting certificates controller
I1114 13:20:24.148246       1 controller.go:68] Starting clusterissuers controller
I1114 13:20:24.148282       1 controller.go:68] Starting ingress-shim controller
```
## Rancher 2.1のインストール

2018年11月12日時点では正常な動作に必要なチャートへのオプションの追加が
Rancher公式のチャートリポジトリに上がっているチャートではできない状態だったので、
最新のチャートの設定をGithubのリポジトリからダウンロードして適用します。

```bash:Rancher2.xのインストール
$ git clone https://github.com/rancher/server-chart.git
$ cd server-chart/rancher
$ helm install . \
  --name rancher \
  --namespace cattle-system \
  --set hostname=rancher.example.com\
  --set replicas=1 \
  --set ingress.extraAnnotations."kubernetes\.io/ingress\.class"="nginx"
```

Nginx Ingress Controllerを利用するため、
`--set ingress.extraAnnotations."kubernetes\.io/ingress\.class"="nginx"`を追加しています。
また、Rancherにアクセスする際のFQDNとして`rancher.example.com`を`--set hostname=rancher.example.com`で指定します。
ここで指定したドメイン(`example.com`)は実際には、ご自身のアカウントのCloud DNSで利用可能なドメインを指定してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/a80a02cd-4767-40ac-dad6-fa6b31260d36.png)

すべてのPodが起動し、DNSを使って名前解決が可能になったタイミングでWebブラウザでアクセス & 初期設定を完了させると
Rancher 2.1のGKE上のk8sクラスタへのインストールは完了です。