Centos7サーバーで1からKubernetes環境を構築しIngressでの外部公開・TLSの設定まで行う

今回の記事では、**Centos7サーバーで1からKubernetes環境を構築し、Ingressでの外部公開・TLSの設定まで行う手順**についてまとめていきたいと思います。

今回は、本番環境を試すような設定をしたいと思っているため、CentOS7サーバー1台でマスターノードとワーカーので両方を稼働させるような構築をします。

#前提条件
- CentOS7のサーバー1台が稼働している。
- Route53にドメインの登録が完了している。

#Docker・Kubernetesの初期設定
#### システムアップデートを行う

```
# yum update
```

#### swapを無効にする

kubeletを正常に動作させるため、SWAPの無効化が必要になる。

```
# swapoff -a
```

#### SWAPの無効を永続化

```text:/etc/fstab
# /dev/mapper/centos-swap swap                    swap    defaults        0 0
```
#### Dockerのインストールと起動

```
# yum install yum-utils device-mapper-persistent-data lvm2
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum install docker-ce
# mkdir -m 644 /etc/docker
```

```json:/etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
```

```
# systemctl enable docker && systemctl start docker
```

#### Kubernetesのインストールと起動

クラスター構築は[kubeadm](https://kubernetes.io/docs/reference/setup-tools/kubeadm/)を使用。

```text:/etc/yum.repos.d/kube-rnetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
```

```
# yum install kubelet kubeadm --disableexcludes=kubernetes
# systemctl enable kubelet && systemctl start kubelet
```


#### Kubernetesに必要なポートを解放

```
# firewall-cmd --permanent --new-zone=k8s
# firewall-cmd --permanent --zone=k8s --add-port 6443/tcp
# firewall-cmd --permanent --zone=k8s --add-port 2379-2380/tcp
# firewall-cmd --permanent --zone=k8s --add-port 10250/tcp
# firewall-cmd --permanent --zone=k8s --add-port 10251/tcp
# firewall-cmd --permanent --zone=k8s --add-port 10252/tcp
# firewall-cmd --permanent --zone=k8s --add-port 30000-32767/tcp
# firewall-cmd --reload
```

#### Kubernetesクラスターの初期構築と設定

バージョン指定が間違っているとエラーが出るので、エラー内容に従って各環境でバージョン指定を行なってください。

```
# echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
# kubeadm init  --pod-network-cidr=10.244.0.0/16 --kubernetes-version v1.22.2
```

```
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

#### （Kubernetesクラスターの初期構築と設定に失敗した場合）

エラーなどが出て失敗した場合は、resetしてやり直す。

```
# kubeadm reset
# echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
# kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version v1.22.2
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

#### flannelをインストールする

コンテナ間通信を行うために必要で、これがないとYAMLファイルを実行してもPod生成が< pending >で止まってしまう。
またコンテナ間通信には、bridgeネットワークcni0の接続を許可するfirewallの設定が必要。


```
# firewall-cmd --permanent --zone=trusted --change-interface=cni0
# firewall-cmd --reload
```

```
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
```

#### 1台でマスターノードとワーカーノードの両方の役割を持つ設定に変える

デフォルトではマスターノードとワーカーノードは別々のサーバーで動かす前提となっているため、今回の1台のサーバーで両方の役割を持つ設定に変える。

```
# kubectl taint nodes --all node-role.kubernetes.io/master-
```

#### テストでDeploymentのYAMLを実行

```yml:deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.17
```

```
# kubectl apply -f deploy.yml
```

```
# kubectl get pod
NAME                                                           READY   STATUS    RESTARTS         AGE
nginx-deployment-db719865c-nnf24                               1/1     Running   0                17s
nginx-deployment-db744865c-sklvc                               1/1     Running   0                17s
```

#TLSの設定
Route53で設定したドメインについて、Let's EncryptのDNSの認証を行う。
Kubernetes上でTLSの設定を自動化できる[cert-manager](https://cert-manager.io/docs/)を使用。

#### cert-managerのインストール


Kubernetes上でTLS証明書の発行、更新、管理を自動化してくれる。

```
# kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
```

#### Route53にアクセス権を持つIAMを作成

クラスターからRoute53にリモートアクセスするため、IAMの作成をAWSであらかじめ行う。
[公式の設定方法](https://cert-manager.io/docs/configuration/acme/dns01/route53/)


#### IAMのシークレットアクセスキーをクラスター内に登録

Secretリソースをroute53-credentials-secretという名前で登録。

```
# kubectl -n  cert-manager create secret generic route53-credentials-secret --from-literal=secret-access-key=<SECRET_ACCESS_KEY>
```

#### ClusterIssuerの作成

証明書を要求するためのClusterIssuer（クラスター全体で使えるIssuer）を作成。
severに関しては一旦テストで実行したのち、問題なければ本番で実行する。

```yml:letsencrypte-issuer.yml
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: letsencrypt-issuer
spec:
  acme:
    # server: https://acme-v02.api.letsencrypt.org/directory #本番
    server: https://acme-staging-v02.api.letsencrypt.org/directory #テスト
    email: <Mail_Address>
    privateKeySecretRef:
      name: letsencrypt-issuer
    solvers:
      - selector:
          dnsZones:
          - "test.com" #Route53で設定しているドメイン名
        dns01:
          route53:
            region: ap-northeast-1
            accessKeyID: <ACCESS_KEY>
            secretAccessKeySecretRef:
              name: route53-credentials-secret #登録したSecretリソース
              key: secret-access-key
```
```
# kubectl apply -f letsencrypte-issuer.yml
# kubectl describe clusterissuer
```
```
Status:
  Acme:
    Last Registered Email:  <Mail_Address>
    Uri:                    https://acme-v02.api.letsencrypt.org/acme/acct/xxxxxxxx
  Conditions:
    Last Transition Time:  2021-09-21T05:28:09Z
    Message:               The ACME account was registered with the ACME server
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
Events:                    <none>
```

#### Certificateの作成

証明書の作成を行う。

```yml:certificate.yml
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: test-com
spec:
  secretName: test-com-tls
  duration: 2160h
  renewBefore: 360h
  organization:
  - test
  commonName: "*.test.com"
  isCA: false
  keySize: 2048
  keyAlgorithm: rsa
  keyEncoding: pkcs1
  usages:
    - server auth
    - client auth
  dnsNames:
  - test.com
  - "*.test.com"
  issuerRef:
    name: letsencrypt-issuer
    kind: ClusterIssuer
```

```
# kubectl apply -f certificate.yml
```

しばらく経ったのち、成功すればtest-com-tlsが作成される。

```
# kubectl describe certificate -A
---
 Normal  Issued        30m   cert-manager  Certificate issued successfully
---
```

```
# kubectl describe secret test-com-tls
```

#Ingressの設定
設定したTLSとIngressリソースを使って、ドメイン名でTLSの外部公開を行う。

#### Nginx Ingress Controllerをインストール


Ingressを外部公開して使うためには、Nginx Ingress Controllerのインストールが必要。

```
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml
```

今回は外部のロードバランサーなどを使用しないため、以下を編集し追記する。

```
# kubectl edit service ingress-nginx-controller -n ingress-nginx
---
  type: LoadBalancer
  externalIPs:
  - <SERVER_IP>　#自身のサーバーのIPアドレス
---
```

#### テストでNGINXのトップページを表示

Deploymentに関しては、上記で記載したdeployment.ymlを使用。

```yml:service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: ClusterIP
  ports:
    - port: 80
  selector:
    app: nginx
```
```yml:ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
    kubernetes.io/tls-acme: "true"
    ingress.kubernetes.io/ssl-redirect: "false"
    cert-manager.io/cluster-issuer: "letsencrypt-issuer"
spec:
  tls:
  - hosts:
      - example.test.com #Route53で登録したAレコードのドメイン名
    secretName: test-com-tls
  rules:
    - host: example.test.com #Route53で登録したAレコードのドメイン名
      http:
        paths:
          - backend:
              service:
                name: nginx-service
                port:
                  number: 80
            path: /
            pathType: Prefix
```

Hostで記載したURLのhttpsにアクセスし、Nginxのトップページがひらけば成功。

![demo](https://gyazo.com/e2d9a211e0d228aad177f10fda4c0cf6/raw)




参考にさせていただいた記事のURL
-
https://qiita.com/shikigamix/items/3f3078cb4c9883554689
https://qiita.com/zembutsu/items/399774c5071050f07975
https://qiita.com/jlandowner/items/9f3c4c0a03d2ae3d2189
https://qiita.com/iqustechtips/items/1ec6b32a98b3fab427d6