Tag: kubernetes

  • วิธีการติดตั้ง Kubernetes Add-on DNS และ DashBoard

    Kubernetes มี DNS กับ GUI ให้ใช้งานบ้างไหม

                หลังจากติดตั้ง Kubernetes แล้วการสร้าง containner โดยในที่นี้เรียกว่า pod (ใช้เรียก 1 containner หรือกลุ่มของ containner ก็ได้) ซึ่งสามารถสร้างด้วยคำสั่ง Kubectl ได้เลย (สร้างจากที่ไหนก็ได้) สำหรับผู้ที่ยังไม่ได้ติดตั้ง ต้องติดตั้งก่อนตามวิธีติดตั้ง Kubernetes บน CoreOS ตอนที่ 1[1] และ ตอนที่ 2[2] 

    สำหรับ Add-on ที่แนะนำจะเป็น DNS และ Dashboard ซึ่งเรียกได้ว่าจำเป็นต้องมี ไม่งั้นชีวิตจะยุ่งยากขึ้นเยอะครับ คงไม่มีใครอยากดูรายการ pod เยอะ ๆ ด้วย command line กันนะครับ

     วิธีการติดตั้ง DNS-Addon[3]

    • เข้าไปยังเครื่องที่ติดตั้ง Kubectl ไว้แล้ว ทำการสร้าง yaml file ดังนี้ (ถ้า vim วางแล้วเพี้ยนให้ใช้ nano แทน)
      nano dns-addon.yaml

      เนื้อหาในไฟล์ดังนี้ (อย่าลืมเปลี่ยน > เป็น > เวลา Copy & Paste ด้วยครับ)

      apiVersion: v1
      kind: Service
      metadata:
        name: kube-dns
        namespace: kube-system
        labels:
          k8s-app: kube-dns
          kubernetes.io/cluster-service: "true"
          kubernetes.io/name: "KubeDNS"
      spec:
        selector:
          k8s-app: kube-dns
        clusterIP: <DNS Cluster-IP>
        ports:
        - name: dns
          port: 53
          protocol: UDP
        - name: dns-tcp
          port: 53
          protocol: TCP
      
      
      ---
      
      
      apiVersion: v1
      kind: ReplicationController
      metadata:
        name: kube-dns-v20
        namespace: kube-system
        labels:
          k8s-app: kube-dns
          version: v20
          kubernetes.io/cluster-service: "true"
      spec:
        replicas: 1
        selector:
          k8s-app: kube-dns
          version: v20
        template:
          metadata:
            labels:
              k8s-app: kube-dns
              version: v20
            annotations:
              scheduler.alpha.kubernetes.io/critical-pod: ''
              scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
          spec:
            containers:
            - name: kubedns
              image: gcr.io/google_containers/kubedns-amd64:1.9
              resources:
                limits:
                  memory: 170Mi
                requests:
                  cpu: 100m
                  memory: 70Mi
              livenessProbe:
                httpGet:
                  path: /healthz-kubedns
                  port: 8080
                  scheme: HTTP
                initialDelaySeconds: 60
                timeoutSeconds: 5
                successThreshold: 1
                failureThreshold: 5
              readinessProbe:
                httpGet:
                  path: /readiness
                  port: 8081
                  scheme: HTTP
                initialDelaySeconds: 3
                timeoutSeconds: 5
              args:
              - --domain=cluster.local.
              - --dns-port=10053
              ports:
              - containerPort: 10053
                name: dns-local
                protocol: UDP
              - containerPort: 10053
                name: dns-tcp-local
                protocol: TCP
            - name: dnsmasq
              image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
              livenessProbe:
                httpGet:
                  path: /healthz-dnsmasq
                  port: 8080
                  scheme: HTTP
                initialDelaySeconds: 60
                timeoutSeconds: 5
                successThreshold: 1
                failureThreshold: 5
              args:
              - --cache-size=1000
              - --no-resolv
              - --server=127.0.0.1#10053
              - --log-facility=-
              ports:
              - containerPort: 53
                name: dns
                protocol: UDP
              - containerPort: 53
                name: dns-tcp
                protocol: TCP
            - name: healthz
              image: gcr.io/google_containers/exechealthz-amd64:1.2
              resources:
                limits:
                  memory: 50Mi
                requests:
                  cpu: 10m
                  memory: 50Mi
              args:
              - --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 > /dev/null
              - --url=/healthz-dnsmasq
              - --cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1:10053 > /dev/null
              - --url=/healthz-kubedns
              - --port=8080
              - --quiet
              ports:
              - containerPort: 8080
                protocol: TCP
            dnsPolicy: Default
    • จากนั้นทำการสร้าง pod ดังนี้
      kubectl create -f dns-addon.yaml
    • สามารถตรวจสอบสถานะการสร้าง pod และ log ได้ดังนี้
      kubectl get pods --namespace=kube-system
      kubectl logs kube-dns-v20-xxxxx -n=kube-system dnsmasq
    • โดยอันที่จริงมีอีกหลายแบบครับ มีแบบ auto scale ก็มีครับ ลองศึกษาดูใน Internet ครับ

      วิธีการติดตั้ง Dashboard-Addon[3]

    • เข้าไปยังเครื่องที่ติดตั้ง Kubectl ไว้แล้ว ทำการสร้าง yaml file ดังนี้ (ถ้า vim วางแล้วเพี้ยนให้ใช้ nano แทน)
      nano kube-dashboard-rc.yaml

      เนื้อหาในไฟล์ดังนี้

      apiVersion: v1
      kind: ReplicationController
      metadata:
        name: kubernetes-dashboard-v1.6.1
        namespace: kube-system
        labels:
          k8s-app: kubernetes-dashboard
          version: v1.6.1
          kubernetes.io/cluster-service: "true"
      spec:
        replicas: 1
        selector:
          k8s-app: kubernetes-dashboard
        template:
          metadata:
            labels:
              k8s-app: kubernetes-dashboard
              version: v1.6.1
              kubernetes.io/cluster-service: "true"
            annotations:
              scheduler.alpha.kubernetes.io/critical-pod: ''
              scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
          spec:
            containers:
            - name: kubernetes-dashboard
              image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.6.1
              resources:
                limits:
                  cpu: 100m
                  memory: 50Mi
                requests:
                  cpu: 100m
                  memory: 50Mi
              ports:
              - containerPort: 9090
              livenessProbe:
                httpGet:
                  path: /
                  port: 9090
                initialDelaySeconds: 30
                timeoutSeconds: 30
    • จากนั้นสร้างอีกไฟล์ดังนี้
      nano kube-dashboard-svc.yaml

      เนื้อหาในไฟล์ดังนี้

      apiVersion: v1
      kind: Service
      metadata:
        name: kubernetes-dashboard
        namespace: kube-system
        labels:
          k8s-app: kubernetes-dashboard
          kubernetes.io/cluster-service: "true"
      spec:
        selector:
          k8s-app: kubernetes-dashboard
        ports:
        - port: 80
          targetPort: 9090
    • จากนั้นทำการสร้าง pod ดังนี้
      kubectl create -f kube-dashboard-rc.yaml
      kubectl create -f kube-dashboard-svc.yaml
    • สามารถตรวจสอบสถานะการสร้าง pod และทำการ forward port ได้ดังนี้
      kubectl get pods --namespace=kube-system
      kubectl port-forward kubernetes-dashboard-v1.6.1-XXXX 9090 --namespace=kube-system

       

    • หลังจากนั้นสามารถทดสอบเปิด Browser บนเครื่องที่รัน kubectl เพื่อทดสอบได้เลย (สามารถเปิดใช้งานได้ 2 วิธีคือผ่านช่องทางปกติ หรือใช้ kubectl ดึงมาจาก pod โดยตรงแล้วทำการ forward port ก็ได้)

                      จะเห็นว่าถ้าเป็น web จะดูอะไรก็ง่ายขึ้นเยอะครับ แต่เนื่องจากไม่มีระบบ login ก็ต้องระวังดี ๆ ถ้าจะเปิดให้ใครก็ได้ใช้งาน อาจต้องสร้าง proxy ดักให้ใส่รหัสผ่านก่อนชั้นหนึ่ง หรือจะเน้นใช้ command line อย่างเดียวก็ได้ครับ….

    ==================================

    Reference :

    [1] รู้จักกับ Kubernetes และวิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 1 Master Node) : https://sysadmin.psu.ac.th/2017/05/17/setup-kubernetes-coreos-section-1/

    [2] วิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 2 Worker Node) : https://sysadmin.psu.ac.th/2017/05/27/setup-kubernetes-coreos-section-2/

    [3] CoreOS -> Deploy Add-ons : https://coreos.com/kubernetes/docs/latest/deploy-addons.html

     

  • วิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 2 Worker Node)

    ถ้าต้องการระบบจัดการ docker container สักตัวต้องทำอย่างไร (ตอนที่ 2)

                จากตอนก่อนหน้านี้ รู้จักกับ Kubernetes และวิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 1 Master Node)[1] ก็มาต่อด้วยการติดตั้งบนเครื่อง Worker ต่อครับ

     วิธีการติดตั้ง Kubernetes Worker Node[2]

    • ทำการติดตั้ง CoreOS บน Worker Node
    • สร้าง directory ดังนี้
      sudo mkdir -p /etc/kubernetes/ssl
    • ทำการ copy ที่สร้างไว้ก่อนหน้านี้มาไว้ใน folder ดังนี้
      File: /etc/kubernetes/ssl/ca.pem
      File: /etc/kubernetes/ssl/${WORKER_FQDN}-worker.pem
      File: /etc/kubernetes/ssl/${WORKER_FQDN}-worker-key.pem
    • เปลี่ยน permission และ owner file เฉพาะไฟล์ -key* ดังนี้
      sudo chmod 600 /etc/kubernetes/ssl/*-key.pem
      sudo chown root:root /etc/kubernetes/ssl/*-key.pem
    • ทำการทำ link เผื่อให้ config แต่ละ worker เหมือน ๆ กัน
      cd /etc/kubernetes/ssl/
      sudo ln -s ${WORKER_FQDN}-worker.pem worker.pem
      sudo ln -s ${WORKER_FQDN}-worker-key.pem worker-key.pem
    • จากนั้นตั้งค่า flannel network เป็น network ที่เอาไว้เชื่อมแต่ละ pod ให้สามารถคุยกันได้ข้ามเครื่อง เพื่อสร้างวง virtual ip ให้กับ pod ดังนี้
      sudo mkdir /etc/flannel

      ทำการสร้างไฟล์ option.env

      sudo vim /etc/flannel/options.env

      เนื้อหาในไฟล์ดังนี้

      FLANNELD_IFACE=<Worker IP>
      FLANNELD_ETCD_ENDPOINTS=http://<Master IP>:2379,http://<Node1 IP>:2379,http://<Node2 IP>:2379
    • จากนั้นทำการสร้าง flannel service ดังนี้
      sudo mkdir -p /etc/systemd/system/flanneld.service.d/
      sudo vim /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 โดยสร้างไฟล์ config ดังนี้
      sudo mkdir -p /etc/systemd/system/docker.service.d
      sudo vim /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_opts_cni.env ขึ้นมาประกอบดังนี้

      sudo mkdir -p /etc/kubernetes/cni
      sudo vim /etc/kubernetes/cni/docker_opts_cni.env

      เนื้อหาในไฟล์ดังนี้

      DOCKER_OPT_BIP=""
      DOCKER_OPT_IPMASQ=""
    • จากนั้นทำการ restart docker service สักรอบดังนี้
      sudo systemctl restart docker
    • หนังจากนั้นทำการสร้าง config ไฟล์สุดท้ายสำหรับ flannel ดังนี้
      sudo mkdir -p /etc/kubernetes/cni/net.d
      sudo vim /etc/kubernetes/cni/net.d/10-flannel.conf

      เนื้อหาในไฟล์ดังนี้

      {
       "name": "podnet",
       "type": "flannel",
       "delegate": {
       "isDefaultGateway": true
       }
      }
    • ทำการ start flannel service และตรวจสถานะการทำงานดู
      sudo systemctl start flanneld
      sudo systemctl enable flanneld
      sudo systemctl status flanneld
    • จากนั้นทำการสร้าง kubelet service ดังนี้
      sudo vim /etc/systemd/system/kubelet.service

      เนื้อหาในไฟล์ดังนี้ (KUBELET_IMAGE_TAG version สามารถตรวจสอบล่าสุดได้ที่ https://quay.io/repository/coreos/hyperkube?tab=tags)

      [Service]
      Environment=KUBELET_IMAGE_TAG=v1.6.2_coreos.0
      Environment="RKT_RUN_ARGS=--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=https://<Master_IP> \
        --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 \
        --cluster_dns=<DNS_SERVICE_IP> \
        --cluster_domain=<CLUSTER_DNS_NAME> \
        --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
    • ทำการ start kubelet service และตรวจสถานะการทำงานดู (ต้องรอสักพักเพราะ service จะต้องโหลด image มาติดตั้งให้ในการ start ครั้งแรก สามารถใช้คำสั่ง journalctl -xe เพื่อตรวจสอบสถานะการทำงาน) ซึ่งจะพบว่ายัง error เพราะยังไม่ได้ลง kube-apiserver (แนะนำลงตัวอื่นให้เสร็จให้หมดแล้วค่อยมา start kubelet service ก็ได้)
      sudo systemctl start kubelet
      sudo systemctl enable kubelet
      sudo systemctl status kubelet
    • หลังจากนั้นทำการติดตั้ง kube-proxy ดังนี้
      sudo vim /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.6.2_coreos.0
          command:
          - /hyperkube
          - proxy
          - --master=https://${MASTER_IP}
          - --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 ดังนี้
      sudo vim /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
    • ในกรณีที่ต้องการแจ้ง systemd ว่าเรามีการเปลี่ยนข้อมูลใน config และต้องการ rescan ทุกอย่างอีกครั้งให้สั่งดังนี้
      sudo systemctl daemon-reload
    • จากนั้นทดสอบ restart kubelet service ใหม่อีกครั้งและตรวจสอบ status หรือ journalctl -xe เพื่อดูว่าการทำงานปกติหรือไม่ ถ้าไม่แก้ให้ถูกต้องแล้ว restart ใหม่อีกครั้งไปเรื่อย ๆ จนกว่าจะปกติ
      sudo systemctl restart kubelet

      จบไปแล้วครับสำหรับการติดตั้ง worker node ครับ ต่อด้วยการติดตั้ง Kubectl สำหรับตรวจสอบสถานะแต่ละ Node ครับ

    วิธีการติดตั้ง Kubectl[3]

    • ทำการ Download tool ในที่นี้จะติดตั้งลงบนเครื่องอื่นที่ไม่ใช่ coreos (อย่าลืม copy เอา ca.pem,admin.pem,admin-key.pem ไปด้วย) เพราะ coreos ไม่อนุญาติให้เขียนบนพื้นที่ ../bin (จริง ๆ ติดตั้งที่ใดก็ได้ OS ใดก็ได้ครับยกตัวอย่าง windows[4]) โดยเลือก Version ให้สอดคล้องกับที่ใช้งานอยู่ครับ
      curl -O https://storage.googleapis.com/kubernetes-release/release/v1.6.2/bin/linux/amd64/kubectl
    • จากนั้นทำการเปลี่ยน permission ให้ execute ได้ และ ทำการ copy ไป global command
      chmod +x kubectl
      sudo mv kubectl /usr/local/sbin/ 
    • จากนั้นทำการตั้งค่าโปรแกรม (ต้องรันทุกครั้งหลังจาก Restart เครื่อง)
      kubectl config set-cluster default-cluster --server=https://<MASTER_IP> --certificate-authority=<cer path>/ca.pem
      kubectl config set-credentials default-admin --certificate-authority=<cer path>/ca.pem, --client-key=<cer path>/admin-key.pem --client-certificate=<cer path>/admin.pem
      kubectl config set-context default-system --cluster=default-cluster --user=default-admin
      kubectl config use-context default-system
    • จากนั้นจะสามารถใช้คำสั่งตรวจสอบสถานะได้ดังนี้
      ./kubectl get nodes

    จบไปแล้วครับสำหรับวิธีติดตั้ง Worker Node และ Kubectl ถ้าทำไม่ได้ลองทำซ้ำ ๆ ดูครับ ลองดู docker logs <containner_id> ตรวจดูปัญหาใน docker และ journalctl -xe เพื่อตรวจสอบ service ดูครับ…..

    ==================================

    Reference :

    [1] รู้จักกับ Kubernetes และวิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 1 Master Node) : https://sysadmin.psu.ac.th/2017/05/17/setup-kubernetes-coreos-section-1/

    [2] CoreOS -> Deploy Kubernetes Worker Node(s) : https://coreos.com/kubernetes/docs/latest/deploy-workers.html

    [3] CoreOS -> Setting up kubectl : https://coreos.com/kubernetes/docs/latest/configure-kubectl.html

    [4] Running kubectl on Windows : https://github.com/eirslett/kubectl-windows

  • รู้จักกับ Kubernetes และวิธีติดตั้ง Kubernetes ด้วย CoreOS (ตอนที่ 1 Master Node)

    ถ้าต้องการระบบจัดการ docker container สักตัวต้องทำอย่างไร

                เมื่อกล่าวถึงระบบจัดการ docker container สักตัวหนึ่ง มักจะกล่าวถึง opensource ตัวหนึ่งชื่อ kubernetes ซึ่งเป็นเครื่องมือที่พัฒนาขึ้นมาด้วย Google[1] ซึ่งสามารถรองรับทั้งในส่วนของ Google Container Engine และ CoreOS จริง ๆ ลงได้บนอีกหลาย platform แต่สำหรับ CoreOS ได้ออกแบบมาให้รองรับ Kubernetes ทำให้การติดตั้งง่ายและสมบูรณ์มากขึ้น (อ่านไปเรื่อย ๆ จะสงสัยนี่ง่ายแล้วเหรอ แต่หลังจากเขียนบทความนี้เสร็จก็มีตัวติดตั้งตัวใหม่ชื่อ Tectonic[6] น่าจะเป็นตัวที่ทำให้การติดตั้งง่ายขึ้นครับ)

                Kubernetes เป็นเครื่องมือที่ช่วย build, deploy และ scale ให้เป็นเรื่องง่าย ๆ และสามารถ replicate containner ได้ง่ายมาก การติดตั้ง Kubernetes บน Google Container Engine ง่ายมาก แต่การติดตั้งบน CoreOS จะยากกว่า ซึ่งสามารถติดตั้งแบบ Single Node และ Multi-Node ซึ่งถ้าจะทำ Multi-Node ต้องเชื่อมต่อไปยัง etcd service ที่ติดตั้งบน CoreOS Cluster ด้วยก็จะดีครับ (ไม่งั้นเป็น Cluster ที่ไม่สมบูรณ์) สามารถอ่านเพิ่มเติมได้ที่วิธีการติดตั้ง CoreOS Cluster[2] (ในบทความใช้ก่อนหน้านี้ CoreOS Cluster เขียนในส่วน ETCD Version 2 แต่การใช้งานกับ Kubernetes ต้องใช้ ETCD Version 3 ตอนนี้ยังไม่มีบทความเสริมในส่วนนี้ อาจจะต้องหาข้อมูลเองก่อนครับ จริง ๆ มีวิธีแต่ยังยากในการเขียนบทความ ไว้ค่อยเขียนเพิ่มให้อีกทีครับ) ซึ่งแน่นอนระหว่าง master node และ worker node มีการตรวจสอบเรื่อง certificate ระหว่าง service ด้วย

                ตัวอย่าง Diagram ของระบบทั้งหมด[3]

    เรียนรู้การค่าเบื้องต้นก่อนการติดตั้ง[4]

    • MASTER_HOST : คือ ชื่อ host ที่ node ลูกเอาไว้ติดต่อและให้เข้าถึงจาก external client  เช่นเวลาสั่งสร้างเครื่องก็จะสั่งผ่านตัวนี้ ในกรณที่ต้องการทำ HA MASTER_HOST จะถูกใช้เป็น load balance โดยใช้ร่วมกับ DNS name โดยการคุยกันระหว่าง MASTER_HOST และ worker (node ลูก) จะใช้ port 443 และมีการเข้ารหัสและยืนยันด้วย TLS Certificate
    • ETCD_ENDPOINT : คือ บริการของ etcd service ซึ่งมีใน CoreOS Cluster ที่ติดตั้งไว้ ให้ใส่ไปให้หมดว่ามีเครื่องอะไรบ้าง คั่นด้วย , (ในที่นี้ไม่ได้ใช้ fleet สร้างเครื่อง หลังจากลงเสร็จจะใช้ kubectl สร้างแทน)
    • POD_NETWORK : เช่น 10.2.0.0/16 ใช้สำหรับกำหนดวง IP ของ pod (pod คือ ชื่อเรียก container อาจจะแค่ 1 container เหรือเรียกเป็นกลุ่มของหลาย ๆ container ที่สร้างด้วย kubernetes)
    • SERVICE_IP_RANGE : เช่น 10.3.0.0/24 ใช้สำหรับ service cluster VIPs ซึ่งควรจะอยู่คนละวงกับ pod_network ซึ่งเป็น ip ที่ไว้ให้ข้างนอกวงเข้าถึง มักจะเป็น IP สำหรับให้บริการ Service ต่าง ๆ และไว้สำหรับใช้งานคู่กับ kube-proxy
    • K8S_SERVICE_IP : เช่น 10.3.0.1 เป็น IP หนึ่งในวง SERVICE_IP_RANGE เพื่อให้บริการ Kubernetes API Service
    • DNS_SERVICE_IP : เช่น 10.3.0.10 เป็น IP หนึ่งในวง SERVICE_IP_RANGE ใช้สำหรับเป็น VIP ของ DNS Service เพื่อให้บริการ DNS ให้กับ worker แต่ละตัว

    วิธีการตั้งค่า TLS สำหรับ Kubernetes[4]

    • ทำการสร้าง Cluster Root CA  (ทุกไฟล์ต่อจากนี้ทำเก็บไว้ที่ CoreOS สักเครื่องหนึ่ง ถึงเวลาติดตั้ง Master, Worker ค่อยมาโหลดมาใช้ครับ)
      sudo openssl genrsa -out ca-key.pem 2048
      sudo openssl req -x509 -new -nodes -key ca-key.pem -days 10000 -out ca.pem -subj "/CN=kube-ca"

    • ตั้งค่า openssl config สำหรับ api-server โดยการสร้างไฟล์ดังนี้
      vim openssl.cnf

      โดยมีเนื้อหาในไฟล์ดังนี้ (ให้ระบุ IP Service และ Master Host ลงไปด้วย)
      *หมายเหตุ : แทนที่เลข IP ใน <….>

      [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 = <K8S_SERVICE_IP>
      IP.2 = <MASTER_HOST>
    • จากนั้นทำการสร้าง API Server Keypair ดังนี้
      sudo openssl genrsa -out apiserver-key.pem 2048
      sudo openssl req -new -key apiserver-key.pem -out apiserver.csr -subj "/CN=kube-apiserver" -config openssl.cnf
      sudo 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

    • ต่อไปเป็นส่วนของสร้าง Cer ในเครื่องลูกทุกเครื่อง (สร้างทีละเครื่องนะครับ) ทำการสร้างไฟล์ดังนี้
      vim worker-openssl.cnf

      เนื้อหาในไฟล์ดังนี้ แทนที่ WORKER_IP ด้วยเครื่องที่ต้องการ

      [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 = <WORKER_IP>
    • จากนั้นทำการสร้าง Keypair ในแต่ละ Worker ดังนี้ (WORKER_FQDN คือชื่อที่จด domain ไว้ ไม่มีก็ใส่ /etc/hosts เอาก็ได้ครับ แต่ต้องใส่เองทุกเครื่อง)
      sudo openssl genrsa -out ${WORKER_FQDN}-worker-key.pem 2048
      sudo WORKER_IP=${WORKER_IP} openssl req -new -key ${WORKER_FQDN}-worker-key.pem -out ${WORKER_FQDN}-worker.csr -subj "/CN=${WORKER_FQDN}" -config worker-openssl.cnf
      sudo WORKER_IP=${WORKER_IP} openssl x509 -req -in ${WORKER_FQDN}-worker.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out ${WORKER_FQDN}-worker.pem -days 365 -extensions v3_req -extfile worker-openssl.cnf
    • สุดท้ายคือการสร้าง Keypair ของ Cluster Admin
       sudo openssl genrsa -out admin-key.pem 2048
       sudo openssl req -new -key admin-key.pem -out admin.csr -subj "/CN=kube-admin"
       sudo openssl x509 -req -in admin.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out admin.pem -days 365
    • ทำได้ครบแล้วก็จะได้ประมาณดังรูป (ยกตัวอย่างมี  4 worker ใช้วิธีเขียน gen-worker-keypair.sh เพื่อรันหลาย ๆ รอบ ลองหาวิธีเขียนดูเองนะครับ)

    วิธีการตั้งค่า Kubernetes บน CoreOS Cluster[5]

    เพื่อให้การติดตั้งง่ายขึ้น อย่าลืมกำหนดค่าต่าง ๆ จดไว้ก่อน ไม่งั้นจะงงได้ ประมาณนี้ครับ

    ETCD_ENDPOINT=http://a.b.c.d:2379,http://a.b.c.e:2379,http://a.b.c.f:2379
    SERVER_IP_NETWORK=?
    K8S_SERVICE_IP=?
    MASTER_HOST=?
    DNS_SERVICE_IP=?
    POD_NETWORK=?

    ทำการติดตั้ง Master Node

    • ทำการติดตั้ง CoreOS บน Master Node
    • สร้าง directory ดังนี้
      sudo mkdir -p /etc/kubernetes/ssl
    • ทำการ copy ที่สร้างไว้ก่อนหน้านี้มาไว้ใน folder ดังนี้
      File: /etc/kubernetes/ssl/ca.pem
      File: /etc/kubernetes/ssl/apiserver.pem
      File: /etc/kubernetes/ssl/apiserver-key.pem
    • เปลี่ยน permission และ owner file เฉพาะไฟล์ -key* ดังนี้
      sudo chmod 600 /etc/kubernetes/ssl/*-key.pem
      sudo chown root:root /etc/kubernetes/ssl/*-key.pem
    • จากนั้นตั้งค่า flannel network[3] เป็น network ที่เอาไว้เชื่อมแต่ละ pod ให้สามารถคุยกันได้ข้ามเครื่อง (ต้องทำทุก node รวม worker ด้วย) เพื่อสร้างวง virtual ip ให้กับ pod ดังนี้
      sudo mkdir /etc/flannel

      ทำการสร้างไฟล์ option.env

      sudo vim /etc/flannel/options.env

      เนื้อหาในไฟล์ดังนี้

      FLANNELD_IFACE=<Master IP>
      FLANNELD_ETCD_ENDPOINTS=http://<Master IP>:2379,http://<Node1 IP>:2379,http://<Node2 IP>:2379
    • จากนั้นทำการสร้าง flannel service ดังนี้
      sudo mkdir -p /etc/systemd/system/flanneld.service.d/
      sudo vim /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 โดยสร้างไฟล์ config ดังนี้
      sudo mkdir -p /etc/systemd/system/docker.service.d
      sudo vim /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_opts_cni.env ขึ้นมาประกอบดังนี้

      sudo mkdir -p /etc/kubernetes/cni
      sudo vim /etc/kubernetes/cni/docker_opts_cni.env

      เนื้อหาในไฟล์ดังนี้

      DOCKER_OPT_BIP=""
      DOCKER_OPT_IPMASQ=""
    • จากนั้นทำการ restart docker service สักรอบดังนี้
      sudo systemctl restart docker
    • หนังจากนั้นทำการสร้าง config ไฟล์สุดท้ายสำหรับ flannel ดังนี้
      sudo mkdir -p /etc/kubernetes/cni/net.d
      sudo vim /etc/kubernetes/cni/net.d/10-flannel.conf

      เนื้อหาในไฟล์ดังนี้

      {
       "name": "podnet",
       "type": "flannel",
       "delegate": {
       "isDefaultGateway": true
       }
      }
    • ทำการ start flannel service และตรวจสถานะการทำงานดู
      sudo systemctl start flanneld
      sudo systemctl enable flanneld
      sudo systemctl status flanneld
    • จากนั้นทำการสั่งให้ทำ vxlan ผ่าน etcdctl ให้กับทุก node ดังนี้ (เปลี่ยน IP เป็นวงที่ต้องการ)
      sudo etcdctl set /coreos.com/network/config "{\"Network\":\"10.2.0.0/16\",\"Backend\":{\"Type\":\"vxlan\"}}"
    • จากนั้นทำการสร้าง kubelet service ดังนี้
      sudo vim /etc/systemd/system/kubelet.service

      เนื้อหาในไฟล์ดังนี้ (KUBELET_IMAGE_TAG version สามารถตรวจสอบล่าสุดได้ที่ https://quay.io/repository/coreos/hyperkube?tab=tags)

      [Service]
      Environment=KUBELET_IMAGE_TAG=v1.6.2_coreos.0
      Environment="RKT_RUN_ARGS=--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 \
        --container-runtime=docker \
        --allow-privileged=true \
        --pod-manifest-path=/etc/kubernetes/manifests \
        --cluster_dns=<DNS_SERVICE_IP> \
        --cluster_domain=<CLUSTER_DNS_NAME>
      ExecStop=-/usr/bin/rkt stop --uuid-file=/var/run/kubelet-pod.uuid
      Restart=always
      RestartSec=10
      
      [Install]
      WantedBy=multi-user.target
    • ทำการ start kubelet service และตรวจสถานะการทำงานดู (ต้องรอสักพักเพราะ service จะต้องโหลด image มาติดตั้งให้ในการ start ครั้งแรก สามารถใช้คำสั่ง journalctl -xe เพื่อตรวจสอบสถานะการทำงาน) ซึ่งจะพบว่ายัง error เพราะยังไม่ได้ลง kube-apiserver (แนะนำลงตัวอื่นให้เสร็จให้หมดแล้วค่อยมา start kubelet service ก็ได้)
      sudo systemctl start kubelet
      sudo systemctl enable kubelet
      sudo systemctl status kubelet
    • ขั้นตอนต่อไปเป็นการสร้าง Rest API สำหรับจัดการ kubernetes (รวมถึงสามารถติดตั้งหน้าจอ GUI เพื่อควบคุมผ่าน Web ได้) โดยสร้างไฟล์ดังนี้
      sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml

      เนื้อหาในไฟล์มีดังนี้ (ระวังเรื่องวรรคด้วยนะครับ ถ้าจะพิมพ์เองไม่แนะนำ copy ไปแก้ดีกว่า)

      apiVersion: v1
      kind: Pod
      metadata:
        name: kube-apiserver
        namespace: kube-system
      spec:
        hostNetwork: true
        containers:
        - name: kube-apiserver
          image: quay.io/coreos/hyperkube:v1.6.2_coreos.0
          command:
          - /hyperkube
          - apiserver
          - --bind-address=0.0.0.0
          - --etcd-servers=${ETCD_ENDPOINTS1},${ETCD_ENDPOINTS2},${ETCD_ENDPOINTS3}
          - --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 ดังนี้
      sudo vim /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.6.2_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 ใช้ในการทำ scale, replica โดยเป็นตัวควบคุม API อีกชั้นหนึ่ง ทำการสร้างไฟล์ดังนี้
      sudo vim /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.6.2_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
        volumes:
        - hostPath:
            path: /etc/kubernetes/ssl
          name: ssl-certs-kubernetes
        - hostPath:
            path: /usr/share/ca-certificates
          name: ssl-certs-host
    • สำหรับอันสุดท้ายก็จะเป็น kube-scheduler (สำหรับการใช้งานเนื่องจากยังไม่ได้ลองใช้งาน ยังไม่เข้าใจว่าทำงานอย่างไร ถ้าว่างจะมาแก้อีกทีครับ) ทำการสร้างไฟล์ดังนี้
      sudo vim /etc/kubernetes/manifests/kube-scheduler.yaml

      มีเนื้อหาในไฟล์ดังนี้

      apiVersion: v1
      kind: Pod
      metadata:
        name: kube-scheduler
        namespace: kube-system
      spec:
        hostNetwork: true
        containers:
        - name: kube-scheduler
          image: quay.io/coreos/hyperkube:v1.6.2_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
      
    • ในส่วนของ Calico จะใช้สำหรับทำ Network Policy เนื่องจากเป็น Optional จึงขอยังไม่ตั้งค่าสำหรับบริการนี้
    • ในกรณีที่ต้องการแจ้ง systemd ว่าเรามีการเปลี่ยนข้อมูลใน config และต้องการ rescan ทุกอย่างอีกครั้งให้สั่งดังนี้
      sudo systemctl daemon-reload
    • จากนั้นทดสอบ restart kubelet service ใหม่อีกครั้งและตรวจสอบ status หรือ journalctl -xe เพื่อดูว่าการทำงานปกติหรือไม่ ถ้าไม่แก้ให้ถูกต้องแล้ว restart ใหม่อีกครั้งไปเรื่อย ๆ จนกว่าจะปกติ
      sudo systemctl restart kubelet

      จบตอนแรกไปก่อนนะครับ ตอนต่อไปจะต่อด้วย worker node และ addon อื่น ๆ

    ==================================

    Reference :

    [1] [Kubernetes] Deploy Docker Container บน Google Container Engine : https://www.nomkhonwaan.com/2016/04/12/deploy-docker-container-on-google-container-engine

    [2] วิธีสร้าง CoreOS Cluster : https://sysadmin.psu.ac.th/2017/05/04/setup-coreos-cluster/

    [3] How to Deploy Kubernetes on CoreOS Cluster : https://www.upcloud.com/support/deploy-kubernetes-coreos/

    [4] CoreOS -> Cluster TLS using OpenSSL : https://coreos.com/kubernetes/docs/latest/openssl.html

    [5] CoreOS -> CoreOS + Kubernetes Step By Step : https://coreos.com/kubernetes/docs/latest/getting-started.html

    [6] CoreOS -> Tectonic, Kubernetes cluster orchestrator with enterprise integration  : https://coreos.com/tectonic/docs/latest/