1. 程式人生 > >Kubernetes叢集安裝文件

Kubernetes叢集安裝文件

和我一步步部署 kubernetes 叢集

dashboard

本系列文件介紹使用二進位制部署 kubernetes 叢集的所有步驟,而不是使用 kubeadm 等自動化方式來部署叢集,同時開啟了叢集的TLS安全認證;

在部署的過程中,將詳細列出各元件的啟動引數,給出配置檔案,詳解它們的含義和可能遇到的問題。

部署完成後,你將理解系統各元件的互動原理,進而能快速解決實際問題。

所以本文件主要適合於那些有一定 kubernetes 基礎,想通過一步步部署的方式來學習和了解系統配置、執行原理的人。

專案程式碼中提供了彙總後的markdon和pdf格式的安裝文件,pdf版本文件下載

注:本文件中不包括docker和私有映象倉庫的安裝。

提供所有的配置檔案

叢集安裝時所有元件用到的配置檔案,包含在以下目錄中:

  • etc: service的環境變數配置檔案
  • manifest: kubernetes應用的yaml檔案
  • systemd :systemd serivce配置檔案

叢集詳情

  • Kubernetes 1.6.0
  • Docker 1.12.5(使用yum安裝)
  • Etcd 3.1.5
  • Flanneld 0.7 vxlan 網路
  • TLS 認證通訊 (所有元件,如 etcd、kubernetes master 和 node)
  • RBAC 授權
  • kublet TLS BootStrapping
  • kubedns、dashboard、heapster(influxdb、grafana)、EFK(elasticsearch、fluentd、kibana) 叢集外掛
  • 私有docker映象倉庫harbor(請自行部署,harbor提供離線安裝包,直接使用docker-compose啟動即可)

步驟介紹

一、建立 kubernetes 各元件 TLS 加密通訊的證書和祕鑰

kubernetes 系統的各元件需要使用 TLS 證書對通訊進行加密,本文件使用 CloudFlare 的 PKI 工具集 cfssl 來生成 Certificate Authority (CA) 和其它證書;

生成的 CA 證書和祕鑰檔案如下:

  • ca-key.pem
  • ca.pem
  • kubernetes-key.pem
  • kubernetes.pem
  • kube-proxy.pem
  • kube-proxy-key.pem
  • admin.pem
  • admin-key.pem

使用證書的元件如下:

  • etcd:使用 ca.pem、kubernetes-key.pem、kubernetes.pem;
  • kube-apiserver:使用 ca.pem、kubernetes-key.pem、kubernetes.pem;
  • kubelet:使用 ca.pem;
  • kube-proxy:使用 ca.pem、kube-proxy-key.pem、kube-proxy.pem;
  • kubectl:使用 ca.pem、admin-key.pem、admin.pem;

kube-controllerkube-scheduler 當前需要和 kube-apiserver 部署在同一臺機器上且使用非安全埠通訊,故不需要證書。

安裝 CFSSL

方式一:直接使用二進位制原始碼包安裝

$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ chmod +x cfssl_linux-amd64
$ sudo mv cfssl_linux-amd64 /root/local/bin/cfssl

$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ chmod +x cfssljson_linux-amd64
$ sudo mv cfssljson_linux-amd64 /root/local/bin/cfssljson

$ wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
$ chmod +x cfssl-certinfo_linux-amd64
$ sudo mv cfssl-certinfo_linux-amd64 /root/local/bin/cfssl-certinfo

$ export PATH=/root/local/bin:$PATH

方式二:使用go命令安裝

我們的系統中安裝了Go1.7.5,使用以下命令安裝更快捷:

$go get -u github.com/cloudflare/cfssl/cmd/...
$echo $GOPATH
/usr/local
$ls /usr/local/bin/cfssl*
cfssl cfssl-bundle cfssl-certinfo cfssljson cfssl-newkey cfssl-scan

$GOPATH/bin目錄下得到以cfssl開頭的幾個命令。

建立 CA (Certificate Authority)

建立 CA 配置檔案

$ mkdir /root/ssl
$ cd /root/ssl
$ cfssl print-defaults config > config.json
$ cfssl print-defaults csr > csr.json
$ cat ca-config.json
{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "8760h"
      }
    }
  }
}

欄位說明

  • ca-config.json:可以定義多個 profiles,分別指定不同的過期時間、使用場景等引數;後續在簽名證書時使用某個 profile;
  • signing:表示該證書可用於簽名其它證書;生成的 ca.pem 證書中 CA=TRUE
  • server auth:表示client可以用該 CA 對server提供的證書進行驗證;
  • client auth:表示server可以用該CA對client提供的證書進行驗證;

建立 CA 證書籤名請求

$ cat ca-csr.json
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • “CN”:Common Name,kube-apiserver 從證書中提取該欄位作為請求的使用者名稱 (User Name);瀏覽器使用該欄位驗證網站是否合法;
  • “O”:Organization,kube-apiserver 從證書中提取該欄位作為請求使用者所屬的組 (Group);

生成 CA 證書和私鑰

$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
$ ls ca*
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem

建立 kubernetes 證書

建立 kubernetes 證書籤名請求

$ cat kubernetes-csr.json
{
    "CN": "kubernetes",
    "hosts": [
      "127.0.0.1",
      "172.20.0.112",
      "172.20.0.113",
      "172.20.0.114",
      "172.20.0.115",
      "10.254.0.1",
      "kubernetes",
      "kubernetes.default",
      "kubernetes.default.svc",
      "kubernetes.default.svc.cluster",
      "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
  • 如果 hosts 欄位不為空則需要指定授權使用該證書的 IP 或域名列表,由於該證書後續被 etcd 叢集和 kubernetes master叢集使用,所以上面分別指定了 etcd 叢集、kubernetes master 叢集的主機 IP 和 kubernetes 服務的服務 IP(一般是kue-apiserver 指定的 service-cluster-ip-range 網段的第一個IP,如 10.254.0.1。

生成 kubernetes 證書和私鑰

$ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
$ ls kuberntes*
kubernetes.csr  kubernetes-csr.json  kubernetes-key.pem  kubernetes.pem

或者直接在命令列上指定相關引數:

$ echo '{"CN":"kubernetes","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes -hostname="127.0.0.1,172.20.0.112,172.20.0.113,172.20.0.114,172.20.0.115,kubernetes,kubernetes.default" - | cfssljson -bare kubernetes

建立 admin 證書

建立 admin 證書籤名請求

$ cat admin-csr.json
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
  • 後續 kube-apiserver 使用 RBAC 對客戶端(如 kubeletkube-proxyPod)請求進行授權;
  • kube-apiserver 預定義了一些 RBAC 使用的 RoleBindings,如 cluster-admin 將 Group system:masters 與 Rolecluster-admin 繫結,該 Role 授予了呼叫kube-apiserver所有 API的許可權;
  • OU 指定該證書的 Group 為 system:masterskubelet 使用該證書訪問 kube-apiserver 時 ,由於證書被 CA 簽名,所以認證通過,同時由於證書使用者組為經過預授權的 system:masters,所以被授予訪問所有 API 的許可權;

生成 admin 證書和私鑰

$ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
$ ls admin*
admin.csr  admin-csr.json  admin-key.pem  admin.pem

建立 kube-proxy 證書

建立 kube-proxy 證書籤名請求

$ cat kube-proxy-csr.json
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • CN 指定該證書的 User 為 system:kube-proxy
  • kube-apiserver 預定義的 RoleBinding cluster-admin 將User system:kube-proxy 與 Role system:node-proxier 繫結,該 Role 授予了呼叫 kube-apiserver Proxy 相關 API 的許可權;

生成 kube-proxy 客戶端證書和私鑰

$ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes  kube-proxy-csr.json | cfssljson -bare kube-proxy
$ ls kube-proxy*
kube-proxy.csr  kube-proxy-csr.json  kube-proxy-key.pem  kube-proxy.pem

校驗證書

以 kubernetes 證書為例

使用 opsnssl 命令

$ openssl x509  -noout -text -in  kubernetes.pem
...
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=Kubernetes
        Validity
            Not Before: Apr  5 05:36:00 2017 GMT
            Not After : Apr  5 05:36:00 2018 GMT
        Subject: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=kubernetes
...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier:
                DD:52:04:43:10:13:A9:29:24:17:3A:0E:D7:14:DB:36:F8:6C:E0:E0
            X509v3 Authority Key Identifier:
                keyid:44:04:3B:60:BD:69:78:14:68:AF:A0:41:13:F6:17:07:13:63:58:CD

            X509v3 Subject Alternative Name:
                DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:172.20.0.112, IP Address:172.20.0.113, IP Address:172.20.0.114, IP Address:172.20.0.115, IP Address:10.254.0.1
...
  • 確認 Issuer 欄位的內容和 ca-csr.json 一致;
  • 確認 Subject 欄位的內容和 kubernetes-csr.json 一致;
  • 確認 X509v3 Subject Alternative Name 欄位的內容和 kubernetes-csr.json 一致;
  • 確認 X509v3 Key Usage、Extended Key Usage 欄位的內容和 ca-config.jsonkubernetes profile 一致;

使用 cfssl-certinfo 命令

$ cfssl-certinfo -cert kubernetes.pem
...
{
  "subject": {
    "common_name": "kubernetes",
    "country": "CN",
    "organization": "k8s",
    "organizational_unit": "System",
    "locality": "BeiJing",
    "province": "BeiJing",
    "names": [
      "CN",
      "BeiJing",
      "BeiJing",
      "k8s",
      "System",
      "kubernetes"
    ]
  },
  "issuer": {
    "common_name": "Kubernetes",
    "country": "CN",
    "organization": "k8s",
    "organizational_unit": "System",
    "locality": "BeiJing",
    "province": "BeiJing",
    "names": [
      "CN",
      "BeiJing",
      "BeiJing",
      "k8s",
      "System",
      "Kubernetes"
    ]
  },
  "serial_number": "174360492872423263473151971632292895707129022309",
  "sans": [
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local",
    "127.0.0.1",
    "10.64.3.7",
    "10.254.0.1"
  ],
  "not_before": "2017-04-05T05:36:00Z",
  "not_after": "2018-04-05T05:36:00Z",
  "sigalg": "SHA256WithRSA",
...

分發證書

將生成的證書和祕鑰檔案(字尾名為.pem)拷貝到所有機器的 /etc/kubernetes/ssl 目錄下備用;

$ sudo mkdir -p /etc/kubernetes/ssl
$ sudo cp *.pem /etc/kubernetes/ssl

參考

二、建立 kubeconfig 檔案

kubeletkube-proxy 等 Node 機器上的程序與 Master 機器的 kube-apiserver 程序通訊時需要認證和授權;

kubernetes 1.4 開始支援由 kube-apiserver 為客戶端生成 TLS 證書的 TLS Bootstrapping 功能,這樣就不需要為每個客戶端生成證書了;該功能當前僅支援為 kubelet 生成證書;

建立 TLS Bootstrapping Token

Token auth file

Token可以是任意的包涵128 bit的字串,可以使用安全的隨機數發生器生成。

export BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF

後三行是一句,直接複製上面的指令碼執行即可。

將token.csv發到所有機器(Master 和 Node)的 /etc/kubernetes/ 目錄。

$cp token.csv /etc/kubernetes/

建立 kubelet bootstrapping kubeconfig 檔案

$ cd /etc/kubernetes
$ export KUBE_APISERVER="https://172.20.0.113:6443"
$ # 設定叢集引數
$ kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig
$ # 設定客戶端認證引數
$ kubectl config set-credentials kubelet-bootstrap \
  --token=${BOOTSTRAP_TOKEN} \
  --kubeconfig=bootstrap.kubeconfig
$ # 設定上下文引數
$ kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig
$ # 設定預設上下文
$ kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
  • --embed-certstrue 時表示將 certificate-authority 證書寫入到生成的 bootstrap.kubeconfig 檔案中;
  • 設定客戶端認證引數時沒有指定祕鑰和證書,後續由 kube-apiserver 自動生成;

建立 kube-proxy kubeconfig 檔案

$ export KUBE_APISERVER="https://172.20.0.113:6443"
$ # 設定叢集引數
$ kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig
$ # 設定客戶端認證引數
$ kubectl config set-credentials kube-proxy \
  --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem \
  --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig
$ # 設定上下文引數
$ kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
$ # 設定預設上下文
$ kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
  • 設定叢集引數和客戶端認證引數時 --embed-certs 都為 true,這會將 certificate-authorityclient-certificateclient-key 指向的證書檔案內容寫入到生成的 kube-proxy.kubeconfig 檔案中;
  • kube-proxy.pem 證書中 CN 為 system:kube-proxykube-apiserver 預定義的 RoleBinding cluster-admin 將Usersystem:kube-proxy 與 Role system:node-proxier 繫結,該 Role 授予了呼叫 kube-apiserver Proxy 相關 API 的許可權;

分發 kubeconfig 檔案

將兩個 kubeconfig 檔案分發到所有 Node 機器的 /etc/kubernetes/ 目錄

$ cp bootstrap.kubeconfig kube-proxy.kubeconfig /etc/kubernetes/

三、建立高可用 etcd 叢集

kuberntes 系統使用 etcd 儲存所有資料,本文件介紹部署一個三節點高可用 etcd 叢集的步驟,這三個節點複用 kubernetes master 機器,分別命名為sz-pg-oam-docker-test-001.tendcloud.comsz-pg-oam-docker-test-002.tendcloud.comsz-pg-oam-docker-test-003.tendcloud.com

  • sz-pg-oam-docker-test-001.tendcloud.com:172.20.0.113
  • sz-pg-oam-docker-test-002.tendcloud.com:172.20.0.114
  • sz-pg-oam-docker-test-003.tendcloud.com:172.20.0.115

TLS 認證檔案

需要為 etcd 叢集建立加密通訊的 TLS 證書,這裡複用以前建立的 kubernetes 證書

$ cp ca.pem kubernetes-key.pem kubernetes.pem /etc/kubernetes/ssl
  • kubernetes 證書的 hosts 欄位列表中包含上面三臺機器的 IP,否則後續證書校驗會失敗;

下載二進位制檔案

https://github.com/coreos/etcd/releases 頁面下載最新版本的二進位制檔案

$ https://github.com/coreos/etcd/releases/download/v3.1.5/etcd-v3.1.5-linux-amd64.tar.gz
$ tar -xvf etcd-v3.1.4-linux-amd64.tar.gz
$ sudo mv etcd-v3.1.4-linux-amd64/etcd* /root/local/bin

建立 etcd 的 systemd unit 檔案

注意替換 ETCD_NAMEINTERNAL_IP 變數的值;

$ export ETCD_NAME=sz-pg-oam-docker-test-001.tendcloud.com
$ export INTERNAL_IP=172.20.0.113
$ sudo mkdir -p /var/lib/etcd /var/lib/etcd
$ cat > etcd.service <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
EnvironmentFile=-/etc/etcd/etcd.conf
ExecStart=/root/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
  --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --peer-cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
  --peer-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster sz-pg-oam-docker-test-001.tendcloud.com=https://172.20.0.113:2380,sz-pg-oam-docker-test-002.tendcloud.com=https://172.20.0.114:2380,sz-pg-oam-docker-test-003.tendcloud.com=https://172.20.0.115:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
  • 指定 etcd 的工作目錄為 /var/lib/etcd,資料目錄為 /var/lib/etcd,需在啟動服務前建立這兩個目錄;
  • 為了保證通訊安全,需要指定 etcd 的公私鑰(cert-file和key-file)、Peers 通訊的公私鑰和 CA 證書(peer-cert-file、peer-key-file、peer-trusted-ca-file)、客戶端的CA證書(trusted-ca-file);
  • 建立 kubernetes.pem 證書時使用的 kubernetes-csr.json 檔案的 hosts 欄位包含所有 etcd 節點的 INTERNAL_IP,否則證書校驗會出錯;
  • --initial-cluster-state 值為 new 時,--name 的引數值必須位於 --initial-cluster 列表中;

啟動 etcd 服務

$ sudo mv etcd.service /etc/systemd/system/
$ sudo systemctl daemon-reload
$ sudo systemctl enable etcd
$ sudo systemctl start etcd
$ systemctl status etcd

在所有的 kubernetes master 節點重複上面的步驟,直到所有機器的 etcd 服務都已啟動。

驗證服務

在任一 kubernetes master 機器上執行如下命令:

$ etcdctl \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \
  cluster-health
2017-04-11 15:17:09.082250 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
2017-04-11 15:17:09.083681 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
member 9a2ec640d25672e5 is healthy: got healthy result from https://172.20.0.115:2379
member bc6f27ae3be34308 is healthy: got healthy result from https://172.20.0.114:2379
member e5c92ea26c4edba0 is healthy: got healthy result from https://172.20.0.113:2379
cluster is healthy

結果最後一行為 cluster is healthy 時表示叢集服務正常。

三、建立高可用 etcd 叢集

kuberntes 系統使用 etcd 儲存所有資料,本文件介紹部署一個三節點高可用 etcd 叢集的步驟,這三個節點複用 kubernetes master 機器,分別命名為sz-pg-oam-docker-test-001.tendcloud.comsz-pg-oam-docker-test-002.tendcloud.comsz-pg-oam-docker-test-003.tendcloud.com

  • sz-pg-oam-docker-test-001.tendcloud.com:172.20.0.113
  • sz-pg-oam-docker-test-002.tendcloud.com:172.20.0.114
  • sz-pg-oam-docker-test-003.tendcloud.com:172.20.0.115

TLS 認證檔案

需要為 etcd 叢集建立加密通訊的 TLS 證書,這裡複用以前建立的 kubernetes 證書

$ cp ca.pem kubernetes-key.pem kubernetes.pem /etc/kubernetes/ssl
  • kubernetes 證書的 hosts 欄位列表中包含上面三臺機器的 IP,否則後續證書校驗會失敗;

下載二進位制檔案

https://github.com/coreos/etcd/releases 頁面下載最新版本的二進位制檔案

$ https://github.com/coreos/etcd/releases/download/v3.1.5/etcd-v3.1.5-linux-amd64.tar.gz
$ tar -xvf etcd-v3.1.4-linux-amd64.tar.gz
$ sudo mv etcd-v3.1.4-linux-amd64/etcd* /root/local/bin

建立 etcd 的 systemd unit 檔案

注意替換 ETCD_NAMEINTERNAL_IP 變數的值;

$ export ETCD_NAME=sz-pg-oam-docker-test-001.tendcloud.com
$ export INTERNAL_IP=172.20.0.113
$ sudo mkdir -p /var/lib/etcd /var/lib/etcd
$ cat > etcd.service <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
EnvironmentFile=-/etc/etcd/etcd.conf
ExecStart=/root/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
  --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --peer-cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
  --peer-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster sz-pg-oam-docker-test-001.tendcloud.com=https://172.20.0.113:2380,sz-pg-oam-docker-test-002.tendcloud.com=https://172.20.0.114:2380,sz-pg-oam-docker-test-003.tendcloud.com=https://172.20.0.115:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
  • 指定 etcd 的工作目錄為 /var/lib/etcd,資料目錄為 /var/lib/etcd,需在啟動服務前建立這兩個目錄;
  • 為了保證通訊安全,需要指定 etcd 的公私鑰(cert-file和key-file)、Peers 通訊的公私鑰和 CA 證書(peer-cert-file、peer-key-file、peer-trusted-ca-file)、客戶端的CA證書(trusted-ca-file);
  • 建立 kubernetes.pem 證書時使用的 kubernetes-csr.json 檔案的 hosts 欄位包含所有 etcd 節點的 INTERNAL_IP,否則證書校驗會出錯;
  • --initial-cluster-state 值為 new 時,--name 的引數值必須位於 --initial-cluster 列表中;

啟動 etcd 服務

$ sudo mv etcd.service /etc/systemd/system/
$ sudo systemctl daemon-reload
$ sudo systemctl enable etcd
$ sudo systemctl start etcd
$ systemctl status etcd

在所有的 kubernetes master 節點重複上面的步驟,直到所有機器的 etcd 服務都已啟動。

驗證服務

在任一 kubernetes master 機器上執行如下命令:

$ etcdctl \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \
  cluster-health
2017-04-11 15:17:09.082250 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
2017-04-11 15:17:09.083681 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
member 9a2ec640d25672e5 is healthy: got healthy result from https://172.20.0.115:2379
member bc6f27ae3be34308 is healthy: got healthy result from https://172.20.0.114:2379
member e5c92ea26c4edba0 is healthy: got healthy result from https://172.20.0.113:2379
cluster is healthy

結果最後一行為 cluster is healthy 時表示叢集服務正常。

四、下載和配置 kubectl 命令列工具

本文件介紹下載和配置 kubernetes 叢集命令列工具 kubelet 的步驟。

下載 kubectl

$ wget https://dl.k8s.io/v1.6.0/kubernetes-client-linux-amd64.tar.gz
$ tar -xzvf kubernetes-client-linux-amd64.tar.gz
$ cp kubernetes/client/bin/kube* /usr/bin/
$ chmod a+x /usr/bin/kube*

建立 kubectl kubeconfig 檔案

$ export KUBE_APISERVER="https://172.20.0.113:6443"
$ # 設定叢集引數
$ kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER}
$ # 設定客戶端認證引數
$ kubectl config set-credentials admin \
  --client-certificate=/etc/kubernetes/ssl/admin.pem \
  --embed-certs=true \
  --client-key=/etc/kubernetes/ssl/admin-key.pem
$ # 設定上下文引數
$ kubectl config set-context kubernetes \
  --cluster=kubernetes \
  --user=admin
$ # 設定預設上下文
$ kubectl config use-context kubernetes
  • admin.pem 證書 OU 欄位值為 system:masterskube-apiserver 預定義的 RoleBinding cluster-admin 將 Groupsystem:masters 與 Role cluster-admin 繫結,該 Role 授予了呼叫kube-apiserver 相關 API 的許可權;
  • 生成的 kubeconfig 被儲存到 ~/.kube/config 檔案;

五、部署高可用 kubernetes master 叢集

kubernetes master 節點包含的元件:

  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager

目前這三個元件需要部署在同一臺機器上。

  • kube-schedulerkube-controller-managerkube-apiserver 三者的功能緊密相關;
  • 同時只能有一個 kube-schedulerkube-controller-manager 程序處於工作狀態,如果執行多個,則需要通過選舉產生一個 leader;

本文件記錄部署一個三個節點的高可用 kubernetes master 叢集步驟。(後續建立一個 load balancer 來代理訪問 kube-apiserver 的請求)

TLS 證書檔案

pem和token.csv證書檔案我們在TLS證書和祕鑰這一步中已經建立過了。我們再檢查一下。

$ ls /etc/kubernetes/ssl
admin-key.pem  admin.pem  ca-key.pem  ca.pem  kube-proxy-key.pem  kube-proxy.pem  kubernetes-key.pem  kubernetes.pem

下載最新版本的二進位制檔案

有兩種下載方式

方式一

github release 頁面 下載釋出版 tarball,解壓後再執行下載指令碼

$ wget https://github.com/kubernetes/kubernetes/releases/download/v1.6.0/kubernetes.tar.gz
$ tar -xzvf kubernetes.tar.gz
...
$ cd kubernetes
$ ./cluster/get-kube-binaries.sh
...

方式二

CHANGELOG頁面 下載 clientserver tarball 檔案

server 的 tarball kubernetes-server-linux-amd64.tar.gz 已經包含了 client(kubectl) 二進位制檔案,所以不用單獨下載kubernetes-client-linux-amd64.tar.gz檔案;

$ # wget https://dl.k8s.io/v1.6.0/kubernetes-client-linux-amd64.tar.gz
$ wget https://dl.k8s.io/v1.6.0/kubernetes-server-linux-amd64.tar.gz
$ tar -xzvf kubernetes-server-linux-amd64.tar.gz
...
$ cd kubernetes
$ tar -xzvf  kubernetes-src.tar.gz

將二進位制檔案拷貝到指定路徑

$ cp -r server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kube-proxy,kubelet} /root/local/bin/

配置和啟動 kube-apiserver

建立 kube-apiserver的service配置檔案

serivce配置檔案/usr/lib/systemd/system/kube-apiserver.service內容:

[Unit]
Description=Kubernetes API Service
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
After=etcd.service

[Service]
EnvironmentFile=-/etc/kubernetes/config
EnvironmentFile=-/etc/kubernetes/apiserver
ExecStart=/usr/bin/kube-apiserver \
	    $KUBE_LOGTOSTDERR \
	    $KUBE_LOG_LEVEL \
	    $KUBE_ETCD_SERVERS \
	    $KUBE_API_ADDRESS \
	    $KUBE_API_PORT \
	    $KUBELET_PORT \
	    $KUBE_ALLOW_PRIV \
	    $KUBE_SERVICE_ADDRESSES \
	    $KUBE_ADMISSION_CONTROL \
	    $KUBE_API_ARGS
Restart=on-failure
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

/etc/kubernetes/config檔案的內容為:

###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=true"

# How the controller-manager, scheduler, and proxy find the apiserver
#KUBE_MASTER="--master=http://sz-pg-oam-docker-test-001.tendcloud.com:8080"
KUBE_MASTER="--master=http://172.20.0.113:8080"

該配置檔案同時被kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy使用。

apiserver配置檔案/etc/kubernetes/apiserver內容為:

###
## kubernetes system config
##
## The following values are used to configure the kube-apiserver
##
#
## The address on the local server to listen to.
#KUBE_API_ADDRESS="--insecure-bind-address=sz-pg-oam-docker-test-001.tendcloud.com"
KUBE_API_ADDRESS="--advertise-address=172.20.0.113 --bind-address=172.20.0.113 --insecure-bind-address=172.20.0.113"
#
## The port on the local server to listen on.
#KUBE_API_PORT="--port=8080"
#
## Port minions listen on
#KUBELET_PORT="--kubelet-port=10250"
#
## Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=https://172.20.0.113:2379,172.20.0.114:2379,172.20.0.115:2379"
#
## Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"
#
## default admission control policies
KUBE_ADMISSION_CONTROL="--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota"
#
## Add your own!
KUBE_API_ARGS="--authorization-mode=RBAC --runtime-config=rbac.authorization.k8s.io/v1beta1 --kubelet-https=true --experimental-bootstrap-token-auth --token-auth-file=/etc/kubernetes/token.csv --service-node-port-range=30000-32767 --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem --client-ca-file=/etc/kubernetes/ssl/ca.pem --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem --etcd-cafile=/etc/kubernetes/ssl/ca.pem --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem --enable-swagger-ui=true --apiserver-count=3 --audit-log-maxage=30 --audit-log-maxbackup=3 --audit-log-maxsize=100 --audit-log-path=/var/lib/audit.log --event-ttl=1h"
  • --authorization-mode=RBAC 指定在安全埠使用 RBAC 授權模式,拒絕未通過授權的請求;
  • kube-scheduler、kube-controller-manager 一般和 kube-apiserver 部署在同一臺機器上,它們使用非安全埠和 kube-apiserver通訊;
  • kubelet、kube-proxy、kubectl 部署在其它 Node 節點上,如果通過安全埠訪問 kube-apiserver,則必須先通過 TLS 證書認證,再通過 RBAC 授權;
  • kube-proxy、kubectl 通過在使用的證書裡指定相關的 User、Group 來達到通過 RBAC 授權的目的;
  • 如果使用了 kubelet TLS Boostrap 機制,則不能再指定 --kubelet-certificate-authority--kubelet-client-certificate--kubelet-client-key 選項,否則後續 kube-apiserver 校驗 kubelet 證書時出現 ”x509: certificate signed by unknown authority“ 錯誤;
  • --admission-control 值必須包含 ServiceAccount
  • --bind-address 不能為 127.0.0.1
  • runtime-config配置為rbac.authorization.k8s.io/v1beta1,表示執行時的apiVersion;
  • --service-cluster-ip-range 指定 Service Cluster IP 地址段,該地址段不能路由可達;
  • 預設情況下 kubernetes 物件儲存在 etcd /registry 路徑下,可以通過 --etcd-prefix 引數進行調整;

啟動kube-apiserver

$ systemctl daemon-reload
$ systemctl enable kube-apiserver
$ systemctl start kube-apiserver
$ systemctl status kube-apiserver

配置和啟動 kube-controller-manager

建立 kube-controller-manager的serivce配置檔案

檔案路徑/usr/lib/systemd/system/kube-controller-manager.service

Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
EnvironmentFile=-/etc/kubernetes/config
EnvironmentFile=-/etc/kubernetes/controller-manager
ExecStart=/usr/bin/kube-controller-manager \
	    $KUBE_LOGTOSTDERR \
	    $KUBE_LOG_LEVEL \
	    $KUBE_MASTER \
	    $KUBE_CONTROLLER_MANAGER_ARGS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

配置檔案/etc/kubernetes/controller-manager

###
# The following values are used to configure the kubernetes controller-manager

# defaults from config and apiserver should be adequate

# Add your own!
KUBE_CONTROLLER_MANAGER_ARGS="--address=127.0.0.1 --service-cluster-ip-range=10.254.0.0/16 --cluster-name=kubernetes --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem  --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem --root-ca-file=/etc/kubernetes/ssl/ca.pem --leader-elect=true"
  • --service-cluster-ip-range 引數指定 Cluster 中 Service 的CIDR範圍,該網路在各 Node 間必須路由不可達,必須和 kube-apiserver 中的引數一致;
  • --cluster-signing-* 指定的證書和私鑰檔案用來簽名為 TLS BootStrap 建立的證書和私鑰;
  • --root-ca-file 用來對 kube-apiserver 證書進行校驗,指定該引數後,才會在Pod 容器的 ServiceAccount 中放置該 CA 證書檔案
  • --address 值必須為 127.0.0.1,因為當前 kube-apiserver 期望 scheduler 和 controller-manager 在同一臺機器,否則:
    $ kubectl get componentstatuses
    NAME                 STATUS      MESSAGE                                                                                        ERROR
    scheduler            Unhealthy   Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: getsockopt: connection refused   
    controller-manager   Healthy     ok                                                                                             
    etcd-2               Unhealthy   Get http://172.20.0.113:2379/health: malformed HTTP response "\x15\x03\x01\x00\x02\x02"        
    etcd-0               Healthy     {"health": "true"}                                                                             
    etcd-1               Healthy     {"health": "true"}

啟動 kube-controller-manager

$ systemctl daemon-reload
$ systemctl enable kube-controller-manager
$ systemctl start kube-controller-manager

配置和啟動 kube-scheduler

建立 kube-scheduler的serivce配置檔案

檔案路徑/usr/lib/systemd/system/kube-scheduler.serivce

[Unit]
Description=Kubernetes Scheduler Plugin
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
EnvironmentFile=-/etc/kubernetes/config
EnvironmentFile=-/etc/kubernetes/scheduler
ExecStart=/usr/bin/kube-scheduler \
            $KUBE_LOGTOSTDERR \
            $KUBE_LOG_LEVEL \
            $KUBE_MASTER \
            $KUBE_SCHEDULER_ARGS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

配置檔案/etc/kubernetes/scheduler

###
# kubernetes scheduler config

# default config should be adequate

# Add your own!
KUBE_SCHEDULER_ARGS="--leader-elect=true --address=127.0.0.1"
  • --address 值必須為 127.0.0.1,因為當前 kube-apiserver 期望 scheduler 和 controller-manager 在同一臺機器;

啟動 kube-scheduler

$ systemctl daemon-reload
$ systemctl enable kube-scheduler
$ systemctl start kube-scheduler

驗證 master 節點功能

$ kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health":