CoreOSクラスタにKubernetesを設定する方法

この記事では、**CoreOS**クラスタ上に**Kubernetes**を設定する方法を紹介します。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/kubernetes-on-coreos-cluster_594228)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

#前提条件と目標
まずは基本的な[CoreOSクラスタ](https://www.alibabacloud.com/ja/product/kubernetes)から始めましょう。Alibaba Cloudはすでに設定可能なクラスタを提供しているので、詳細についてはあまり触れないことにします。クラスタに必要なのは、少なくともマスターノードとワーカーノードです。ノードには、Kubernetesの中で専門的な役割を割り当てることにしますが、参考までに、これらのノードは互換性があります。ノードの1つであるマスターは、コントロールマネージャとAPIサーバを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/fdcfc0fc-d910-ec80-4266-03d767a67f83.png)

このチュートリアルでは、CoreOSのWebサイトで公開されている実装[ガイド](https://coreos.com/kubernetes/docs/1.6.1/index.html?spm=a2c65.11461447.0.0.687943f0Q1tCcY)を参考にしました。CoreOS クラスタがすべてセットアップされた状態で、次に進んでみましょう。ここでは、2つのサンプル BareMetal ノードを使用します。

#マスターノード
ノード1をマスターとします。CoreOSノードのSSHから始めます。

certsというディレクトリを作成します。

```
$ mkdir certs
$ cd certs
```

`cert_generator.sh`としてcertsディレクトリに以下のスクリプトを貼り付けます。

```
#!/bin/bash
# Creating TLS certs
echo "Creating CA ROOT**********************************************************************"
openssl genrsa -out ca-key.pem 2048
openssl req -x509 -new -nodes -key ca-key.pem -days 10000 -out ca.pem -subj "/CN=kube-ca"
echo "creating API Server certs*************************************************************"
echo "Enter Master Node IP address:"
read master_Ip
cat >openssl.cnf<<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
IP.1 = 10.3.0.1
IP.2 = $master_Ip
EOF
openssl genrsa -out apiserver-key.pem 2048
openssl req -new -key apiserver-key.pem -out apiserver.csr -subj "/CN=kube-apiserver" -config openssl.cnf
openssl x509 -req -in apiserver.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out apiserver.pem -days 365 -extensions v3_req -extfile openssl.cnf
echo "Creating worker nodes"
cat > worker-openssl.cnf<< EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
IP.1 = \$ENV::WORKER_IP
EOF
echo "Enter the number of worker nodes:"
read worker_node_num
for (( c=1; c<= $worker_node_num; c++ ))
do
   echo "Enter the IP Address for the worker node_$c :"
   read ip
   openssl genrsa -out kube-$c-worker-key.pem 2048
   WORKER_IP=$ip openssl req -new -key kube-$c-worker-key.pem -out kube-$c-worker.csr -subj "/CN=kube-$c" -config worker-openssl.cnf
   WORKER_IP=$ip openssl x509 -req -in kube-$c-worker.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out kube-$c-worker.pem -days 365 -extensions v3_req -extfile worker-openssl.cnf
done
echo "Creating Admin certs********************************************************"
openssl genrsa -out admin-key.pem 2048
openssl req -new -key admin-key.pem -out admin.csr -subj "/CN=kube-admin"
openssl x509 -req -in admin.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out admin.pem -days 365
echo "DONE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
```

実行可能なスクリプトを設定します。

```
$ chmod +x cert_generator.sh
```

実行スクリプトが実行されると、ノードの詳細を入力するように促されるはずです。その後、Kubernetesのインストール上で実行するための証明書を生成します。

以下のように生成された鍵を作成するディレクトリを作成します。

```
$ mkdir -p /etc/kubernetes/ssl
```

certsから以下のcertsを`/etc/kubernetes/ssl`にコピーします。

```
/etc/kubernetes/ssl/ca.pem
/etc/kubernetes/ssl/apiserver.pem
/etc/kubernetes/ssl/apiserver-key.pem
```

#ネットワーク構成
次に、/etc/flannel/options.envにflannelのローカル設定を取得し、etcdにクラスタレベルの設定をソースとして取得するように設定してみましょう。以下の内容を含むスクリプトを作成し、以下の点に注意してください。

1、`${ADVERTISE_IP}`をマシンのパブリックIPに置き換えてください。
2、`${ETCD_ENDPOINTS}`を置き換えてください。

```
FLANNELD_IFACE=${ADVERTISE_IP}
FLANNELD_ETCD_ENDPOINTS=${ETCD_ENDPOINTS}
```

次に、flannel起動時に上記の設定を含むドロップインを以下のように作成します。
`/etc/systemd/system/flanneld.service.d/40-ExecStartPre-symlink.conf`

```
[Service]
ExecStartPre=/usr/bin/ln -sf /etc/flannel/options.env /run/flannel/options.env
```

#Dockerの設定
クラスタのポッドネットワークを管理するために、flannelにDockerを設定しておく必要があります。Dockerが起動する前にflannelが実行されることを要求する必要があります。systemdのドロップイン、`/etc/systemd/system/docker.service.d/40-flannel.conf`を適用してみましょう。

```
[Unit]
Requires=flanneld.service
After=flanneld.service
[Service]
EnvironmentFile=/etc/kubernetes/cni/docker_opts_cni.env
```

Docker CNI Optionsファイルを起動し、`etc/kubernetes/cni/docker_opts_cni.en`

```
DOCKER_OPT_BIP=""
DOCKER_OPT_IPMASQ=""
```

flannelネットワークを使用している場合は、以下のコマンドでflannel CNIの設定を行います。

```
/etc/kubernetes/cni/net.d/10-flannel.conf
{
    "name": "podnet",
    "type": "flannel",
    "delegate": {
        "isDefaultGateway": true
    }
}
```

Kubeletユニットの作成
Kubelet はポッドの起動と停止、その他のマシンレベルのタスクを担当します。先ほどインストールしたTLS証明書を使って、マスターノード上で動作するAPIサーバと通信します。

`etc/systemd/system/kubelet.service`を作成します。

1、`${ADVERTISE_IP}`をこのノードのパブリックIPに置き換えてください。
2、`${DNS_SERVICE_IP} `を`10.3.0.10`に置き換えてください。

```
[Service]
Environment=KUBELET_VERSION=v1.5.1_coreos.0
Environment="RKT_OPTS=--uuid-file-save=/var/run/kubelet-pod.uuid \
  --volume var-log,kind=host,source=/var/log \
  --mount volume=var-log,target=/var/log \
  --volume dns,kind=host,source=/etc/resolv.conf \
  --mount volume=dns,target=/etc/resolv.conf"
ExecStartPre=/usr/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/usr/bin/mkdir -p /var/log/containers
ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/run/kubelet-pod.uuid
ExecStart=/usr/lib/coreos/kubelet-wrapper \
  --api-servers=http://127.0.0.1:8080 \
  --register-schedulable=false \
  --cni-conf-dir=/etc/kubernetes/cni/net.d \
  --network-plugin=cni \
  --container-runtime=docker \
  --allow-privileged=true \
  --pod-manifest-path=/etc/kubernetes/manifests \
  --hostname-override=${ADVERTISE_IP} \
  --cluster_dns=${DNS_SERVICE_IP} \
  --cluster_domain=cluster.local
ExecStop=-/usr/bin/rkt stop --uuid-file=/var/run/kubelet-pod.uuid
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

###kube-apiserverポッドのセットアップ
API サーバーはワークロードの多くを処理し、ほとんどのアクティビティが行われます。API サーバーはステートレスで、リクエストを処理し、フィードバックを提供し、必要に応じて結果を etcd に保存します。

`etc/kubernetes/manifests/kube-apiserver.yaml` を作成します。

1、 `${ETCD_ENDPOINTS}`をCoreOSホストに置き換えてください。
2、`${SERVICE_IP_RANGE}`を`10.3.0.0.0/24`に置き換えてください。
3、`${ADVERTISE_IP} `をこのノードのパブリックIPに置き換えてください。

```
apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  hostNetwork: true
  containers:
  - name: kube-apiserver
    image: quay.io/coreos/hyperkube:v1.5.1_coreos.0
    command:
    - /hyperkube
    - apiserver
    - --bind-address=0.0.0.0
    - --etcd-servers=${ETCD_ENDPOINTS}
    - --allow-privileged=true
    - --service-cluster-ip-range=${SERVICE_IP_RANGE}
    - --secure-port=443
    - --advertise-address=${ADVERTISE_IP}
    - --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
    - --tls-cert-file=/etc/kubernetes/ssl/apiserver.pem
    - --tls-private-key-file=/etc/kubernetes/ssl/apiserver-key.pem
    - --client-ca-file=/etc/kubernetes/ssl/ca.pem
    - --service-account-key-file=/etc/kubernetes/ssl/apiserver-key.pem
    - --runtime-config=extensions/v1beta1/networkpolicies=true
    - --anonymous-auth=false
    livenessProbe:
      httpGet:
        host: 127.0.0.1
        port: 8080
        path: /healthz
      initialDelaySeconds: 15
      timeoutSeconds: 15
    ports:
    - containerPort: 443
      hostPort: 443
      name: https
    - containerPort: 8080
      hostPort: 8080
      name: local
    volumeMounts:
    - mountPath: /etc/kubernetes/ssl
      name: ssl-certs-kubernetes
      readOnly: true
    - mountPath: /etc/ssl/certs
      name: ssl-certs-host
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/ssl
    name: ssl-certs-kubernetes
  - hostPath:
      path: /usr/share/ca-certificates
    name: ssl-certs-host
```

###kube-proxy Podのセットアップ
API サーバで行ったように、サービスやポッドへのトラフィックの誘導を担当するプロキシを実行します。プロキシはAPIサーバと定期的に通信を行うことで最新の情報を提供します。プロキシはクラスタ内のマスターノードとワーカーノードの両方をサポートしています。

設定は必要なく、`/etc/kubernetes/manifests/kube-proxy.yaml`を作成することから始めます。

```
apiVersion: v1
kind: Pod
metadata:
  name: kube-proxy
  namespace: kube-system
spec:
  hostNetwork: true
  containers:
  - name: kube-proxy
    image: quay.io/coreos/hyperkube:v1.5.1_coreos.0
    command:
    - /hyperkube
    - proxy
    - --master=http://127.0.0.1:8080
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: ssl-certs-host
      readOnly: true
  volumes:
  - hostPath:
      path: /usr/share/ca-certificates
    name: ssl-certs-host
```

###kube-controller-manager Podのセットアップ
ディスク内のTLS証明書を使用する`/etc/kubernetes/manifests/kube-controller-manager.yaml`を作成します。

```
apiVersion: v1
kind: Pod
metadata:
  name: kube-controller-manager
  namespace: kube-system
spec:
  hostNetwork: true
  containers:
  - name: kube-controller-manager
    image: quay.io/coreos/hyperkube:v1.5.1_coreos.0
    command:
    - /hyperkube
    - controller-manager
    - --master=http://127.0.0.1:8080
    - --leader-elect=true
    - --service-account-private-key-file=/etc/kubernetes/ssl/apiserver-key.pem
    - --root-ca-file=/etc/kubernetes/ssl/ca.pem
    resources:
      requests:
        cpu: 200m
    livenessProbe:
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 10252
      initialDelaySeconds: 15
      timeoutSeconds: 15
    volumeMounts:
    - mountPath: /etc/kubernetes/ssl
      name: ssl-certs-kubernetes
      readOnly: true
    - mountPath: /etc/ssl/certs
      name: ssl-certs-host
      readOnly: true
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/ssl
    name: ssl-certs-kubernetes
  - hostPath:
      path: /usr/share/ca-certificates
    name: ssl-certs-host
```

###kube-cheduler Podのセットアップ
次に、スケジューラを設定して、APIの予定外のポッドを追跡してマシンを割り当て、その決定をAPに更新します。

`etc/kubernetes/manifests/kube-scheduler.yaml File`を作成します。

```
apiVersion: v1
kind: Pod
metadata:
  name: kube-scheduler
  namespace: kube-system
spec:
  hostNetwork: true
  containers:
  - name: kube-scheduler
    image: quay.io/coreos/hyperkube:v1.5.1_coreos.0
    command:
    - /hyperkube
    - scheduler
    - --master=http://127.0.0.1:8080
    - --leader-elect=true
    resources:
      requests:
        cpu: 100m
    livenessProbe:
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 10251
      initialDelaySeconds: 15
      timeoutSeconds: 15
```

###変化されたユニットを読み込む
このように実装した変更点をすべて再スキャンするようにシステムに指示してみましょう。

```
$ sudo systemctl daemon-reload
```

###Flannelネットワークの設定
etcd がFlannelのクラスタレベルの設定を保存していることはすでに述べました。したがって、ポッドネットワークのIP範囲を設定しておきましょう。etccd はすでに起動しているので、今が設定するのに適したタイミングです。あるいは、etcd を起動して

1、`$POD_NETWORK` の代わりに `10.2.0.0/16` を配置します。
2、`$ETCD_SERVER` の代わりに、`$ETCD_ENDPOINTS` の url `(http://ip:port)` を配置します。

```
$ curl -X PUT -d "value={\"Network\":\"$POD_NETWORK\",\"Backend\":{\"Type\":\"vxlan\"}}" "$ETCD_SERVER/v2/keys/coreos.com/network/config"
```

変更を有効にするためにflannelを再起動します。これはひいては docker デーモンを再起動し、コンテナの実行に影響を与える可能性があります。

```
$ sudo systemctl start flanneld
$ sudo systemctl enable flanneld
```

###Kubeletを起動
これですべての設定が完了し、kubeletを起動する準備が整いました。また、コントローラ、スケジューラ、プロキシ、Pod APIサーバのマニフェストも立ち上げて実行します。

```
$ sudo systemctl start kubelet
```

再起動後にkubeletが起動することを確認してください。

```
$ sudo systemctl enable kubelet
```

#ワーカーノード
ワーカーノードの場合は、まずディレクトリを作成し、ワーカーノードに生成したSSLキーを配置します。

```
$ mkdir -p /etc/kubernetes/ssl
```

**certs**から**/etc/kubernetes/ssl**に貼り付けます。

```
/etc/kubernetes/ssl/ca.pem
/etc/kubernetes/ssl/kube-1-worker-apiserver.pem
/etc/kubernetes/ssl/kube-1-worker-apiserver-key.pem
```

#ネットワーク構成
以前に行ったように、flannelのローカル設定は `/etc/flannel/options.env` から取得し、etcd はクラスタレベルの設定を格納します。このファイルを複製し、必要な調整を行ってください。

1、`${ADVERTISE_IP}`の代わりにマシンのパブリックIPに置き換えてください。
2、`${ETCD_ENDPOINTS}`を置き換えてください。

```
FLANNELD_IFACE=${ADVERTISE_IP}
FLANNELD_ETCD_ENDPOINTS=${ETCD_ENDPOINTS}
```

flannel再起動で上記の構成を使用するためのドロップインを作成します。`/etc/systemd/system/flanneld.service.d/40-ExecStartPre-symlink.conf`

```
[Service].
ExecStartPre=/usr/bin/ln -sf /etc/flannel/options.env /run/flannel/options.env
```

#Dockerの設定
次に、Dockerがクラスタのポッドネットワークを管理するためにflannelを使用するように設定します。方法は上で行った実装と同様で、Dockerが起動する前にflannelを起動する必要があります。

ここでは、`/etc/systemd/system/docker.service.d/40-flannel.conf`という[ systemd drop-in](https://coreos.com/os/docs/latest/using-systemd-drop-in-units.html?spm=a2c65.11461447.0.0.687943f031ACip)を適用してみます。

```
[Unit]
Requires=flanneld.service
After=flanneld.service
[Service]
EnvironmentFile=/etc/kubernetes/cni/docker_opts_cni.env
```

`etc/kubernetes/cni/docker_opts_cni.env`のようにDocker CNI Optionsファイルを起動します。

```
DOCKER_OPT_BIP=""
DOCKER_OPT_IPMASQ=""
```

Flannel ネットワークに依存している場合は、以下のように Flannel CNI の設定を行います。`/etc/kubernetes/cni/net.d/10-flannel.conf`

```
{
    "name": "podnet",
    "type": "flannel",
    "delegate": {
        "isDefaultGateway": true
    }
}
```

#Kubeletユニットの作成
ワーカーノードでは、以下のようなkubeletサービスを作成してみましょう。

`etc/systemd/system/kubelet.service` を作成します。

1、${ADVERTISE_IP}をノードのパブリックIPに置き換える。

2、${DNS_SERVICE_IP}を10.3.0.10に置き換えてください。


3、${MASTER_HOST}を置き換えてください。

```
Environment=KUBELET_VERSION=v1.5.1_coreos.0
Environment="RKT_OPTS=--uuid-file-save=/var/run/kubelet-pod.uuid \
  --volume dns,kind=host,source=/etc/resolv.conf \
  --mount volume=dns,target=/etc/resolv.conf \
  --volume var-log,kind=host,source=/var/log \
  --mount volume=var-log,target=/var/log"
ExecStartPre=/usr/bin/mkdir -p /etc/kubernetes/manifests
ExecStartPre=/usr/bin/mkdir -p /var/log/containers
ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/run/kubelet-pod.uuid
ExecStart=/usr/lib/coreos/kubelet-wrapper \
  --api-servers=${MASTER_HOST} \
  --cni-conf-dir=/etc/kubernetes/cni/net.d \
  --network-plugin=cni \
  --container-runtime=docker \
  --register-node=true \
  --allow-privileged=true \
  --pod-manifest-path=/etc/kubernetes/manifests \
  --hostname-override=${ADVERTISE_IP} \
  --cluster_dns=${DNS_SERVICE_IP} \
  --cluster_domain=cluster.local \
  --kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml \
  --tls-cert-file=/etc/kubernetes/ssl/worker.pem \
  --tls-private-key-file=/etc/kubernetes/ssl/worker-key.pem
ExecStop=-/usr/bin/rkt stop --uuid-file=/var/run/kubelet-pod.uuid
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

###kube-proxy Podの設定
`etc/kubernetes/manifests/kube-proxy.yaml`ファイルを作成します。

```
apiVersion: v1
kind: Pod
metadata:
  name: kube-proxy
  namespace: kube-system
spec:
  hostNetwork: true
  containers:
  - name: kube-proxy
    image: quay.io/coreos/hyperkube:v1.5.1_coreos.0
    command:
    - /hyperkube
    - proxy
    - --master=${MASTER_HOST}
    - --kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: "ssl-certs"
    - mountPath: /etc/kubernetes/worker-kubeconfig.yaml
      name: "kubeconfig"
      readOnly: true
    - mountPath: /etc/kubernetes/ssl
      name: "etc-kube-ssl"
      readOnly: true
  volumes:
  - name: "ssl-certs"
    hostPath:
      path: "/usr/share/ca-certificates"
  - name: "kubeconfig"
    hostPath:
      path: "/etc/kubernetes/worker-kubeconfig.yaml"
  - name: "etc-kube-ssl"
    hostPath:
      path: "/etc/kubernetes/ssl"
```

###Kubeconfigの設定
Kubernetesコンポーネントが安全に通信するためには、認証設定の定義にkubeconfigを使用します。今回のユースケースでは、kubeletとproxyが読み込んだ設定により、それらがAPIと通信できるようにします。

まずファイルを作成します。`/etc/kubernetes/worker-kubeconfig.yaml`を作成します。

```
/etc/kubernetes/worker-kubeconfig.yaml
apiVersion: v1
kind: Config
clusters:
- name: local
  cluster:
    certificate-authority: /etc/kubernetes/ssl/ca.pem
users:
- name: kubelet
  user:
    client-certificate: /etc/kubernetes/ssl/worker.pem
    client-key: /etc/kubernetes/ssl/worker-key.pem
contexts:
- context:
    cluster: local
    user: kubelet
  name: kubelet-context
current-context: kubelet-context
```

###サービスの開始
ワーカーサービスの開始準備が整いました。

###変更した内容の読み込み
このように変更した内容を更新するためにディスクを再スキャンするようにシステムに指示してみましょう。

```
$ sudo systemctl daemon-reload
```

###kubeletとflannelを起動する
kubeletを起動して、プロキシを起動します。

```
$ sudo systemctl start flanneld
$ sudo systemctl start kubelet
```

各ブート時にサービスの起動を強制します。

```
$ sudo systemctl enable flanneld
Created symlink from /etc/systemd/system/multi-user.target.wants/flanneld.service to /etc/systemd/system/flanneld.service.
$ sudo systemctl enable kubelet
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /etc/systemd/system/kubelet.service.
To check the health of the kubelet systemd unit that we created, run systemctl status kubelet.service.
```

#結論
ここまで読んでくださった方、おめでとうございます。KubernetesをCoreOSクラスタ上で実行するように簡単に設定することができます。Kubernetesの詳細については、このチュートリアルの他の記事を参照してください。注意点として、このチュートリアルでは、特にIPアドレスを正しく変更して、クラスタ上で動作させるようにしてください。お疲れ様でした。

Alibaba Cloudのアカウントをお持ちですか？アカウントにサインアップして、[40以上の製品を無料でお試し](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.687943f03P1qxf)ください。詳細については、[Alibaba Cloudの利用を開始する](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.687943f0vfgNvm)を参照してください。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*