k8s入门(2) --- 手动搭建k8s集群

720 阅读6分钟

基础环境准备

准备了三台虚拟机 ,操作系统都是ubuntu20.04ip分别为172.16.42.144172.16.42.145172.16.42.146hostname分别为k8s-01k8s-02k8s-03。虚拟IP172.16.42.143

kubernates使用的版本是1.23.1

关闭swap

所有机器都需要操作,修改/etc/fstab,注释swap相关内容

然后调用

swapoff -a

修改hosts

所有的机器的/etc/hosts中添加

172.16.42.144 k8s-01
172.16.42.145 k8s-02
172.16.42.146 k8s-03

修改ip转发

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.bridge.bridge-nf-call-iptables=1

创建CA证书

k8s中所有的通信都需要用到PKI ,根据PKI证书和要求,我们需要准备多张证书分别用于不同的场景,根据文档,我们需要创建自己的CA。创建证书有很多工具,例如opensslcfssl 或者easyrsa, 这里选择cfssl

获取cfssl

这里主要用的是cfsslcfssljson , 只要在一台服务器上操作即可,也可以在本地基础上把所有的证书生成即可。

##下载cfssl和cfssljson工具
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64

##移动命令
mv cfssl_1.6.1_linux_amd64 /usr/local/bin/cfssl
mv cfssljson_1.6.1_linux_amd64 /usr/local/bin/cfssljson

##赋予可运行权限
chmod a+x cfssl
chmod a+x cfssljson

创建配置文件

CA配置文件用配置根证书的使用场景和具体参数,并保存为ca-config.json

{
  "signing": {
    "default": {
      "expiry": "876000h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
          "signing",
          "key encipherment",
          "server auth",
          "client auth"
        ],
        "expiry": "876000h"
      }
    }
   }
}

其中profiles中的kubernetes可以换成各种你自己喜欢的名字,这名字值只是代表一种使用场景。

创建证书并上传

根据pki体系,所有的证书都需要csr,因此需要先创造证书的csr

先创建ca-csr.json:

{
    "CN": "kubernetes-ca",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C":"CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "k8s",
            "OU": "System"
        }
    ]
}

其中CN的名称是根据PKI 证书和要求-单根CA的描述填写的。

调用cfsslcfssljson命令,生成ca证书

cfssl gencert --initca ca-csr.json | cfssljson -bare ca

会生成三个文件分别是ca.csrca.pemca-key.pem ,生成之后把ca.pemca-key.pem上传到服务器的/etc/kubernetes/certs目录下, 之后所有的证书都会放在该目录下。

创建etcd集群

k8s使用etcd作为所有集群数据的后台数据库,使用集群的话etcd服务的数量需要为奇数,为Kubernetes运行etcd集群

创建etcd证书

创建etcd-csr.json文件:

{
    "CN": "etcd",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
        "127.0.0.1",
        "172.16.42.144",
        "172.16.42.145",
        "172.16.42.146"
    ],
    "names": [
        {
            "C": "CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "k8s",
            "OU": "System"
        }
    ]
}

其中hosts节点是所有部署etcd服务的服务器ip

然后使用cfssl命令生成证书:

 cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd

下载etcd

## 下载etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.5.1/etcd-v3.5.1-linux-amd64.tar.gz

## 解压缩
tar -vaxf etcd-v3.5.1-linux-amd64.tar.gz -C /etc
mv /etc/etcd-v3.5.1-linux-amd64 /etc/etcd

配置服务

创建etcd.service

[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd
[Service]
Type=notify
ExecStart=/etc/etcd/etcd \
    --data-dir=/var/lib/etcd/default.etcd \
    --name=etcd-0 \
    --cert-file=/etc/kubernetes/certs/etcd.pem \
    --key-file=/etc/kubernetes/certs/etcd-key.pem \
    --trusted-ca-file=/etc/kubernetes/certs/ca.pem \
    --peer-cert-file=/etc/kubernetes/certs/etcd.pem \
    --peer-key-file=/etc/kubernetes/certs/etcd-key.pem \
    --peer-trusted-ca-file=/etc/kubernetes/certs/ca.pem \
    --logger=zap \
    --peer-client-cert-auth \
    --client-cert-auth \
    --listen-peer-urls=https://172.16.42.144:2380 \
    --initial-advertise-peer-urls=https://172.16.42.144:2380 \
    --listen-client-urls=https://172.16.42.144:2379,http://127.0.0.1:2379 \
    --advertise-client-urls=https://172.16.42.144:2379 \
    --initial-cluster-token=etcd-cluster\
    --initial-cluster="etcd-0=https://172.16.42.144:2380,etcd-1=https://172.16.42.145:2380,etcd-2=https://172.16.42.146:2380" \
    --initial-cluster-state=new \
    --auto-compaction-mode=periodic \
    --auto-compaction-retention=1 \
    --max-request-bytes=33554432 \
    --quota-backend-bytes=6442450944 \
    --heartbeat-interval=250 \
    --election-timeout=2000
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target

service分发到etcd服务的节点。不同的节点需要对该service进行一些调整,主要修改

  1. --name=etcd-0 修改名称,需要和initial-cluster中的名称匹配
  2. --listen-peer-urls=https://172.16.42.144:2380 172.16.42.144修改为具体的节点的ip
  3. --initial-advertise-peer-urls=https://172.16.42.144:2380 172.16.42.144修改为具体的节点的ip
  4. --listen-client-urls=https://172.16.42.144:2379,http://127.0.0.1:2379 172.16.42.144修改为具体的节点的ip
  5. --advertise-client-urls=https://172.16.42.144:2379 172.16.42.144修改为具体的节点的ip
  6. --initial-cluster="etcd-0=https://172.16.42.144:2380,etcd-1=https://172.16.42.145:2380,etcd-2=https://172.16.42.146:2380" 修改成具体的nameip

启动服务:

systemctl daemon-reloa
systemctl start etcd.service
systemctl enable etcd.service

使用systemctl status etcd.service 看到如下

etcd服务启动成功

验证

export ETCD_ENDPOINTS=https://172.16.42.144:2379,https://172.16.42.145:2379,https://172.16.42.146:2379

/etc/etcd/etcdctl -w table --cacert=/etc/kubernetes/certs/ca.pem --cert=/etc/kubernetes/certs/etcd.pem --key=/etc/kubernetes/certs/etcd-key.pem --endpoints=${ETCD_ENDPOINTS} endpoint status

看到如下输出:

表示该etcd集群启动成功

Master节点

组成

master节点主要由kube-api-server,kube-schedulerkube-controller-manager组成。

wget https://dl.k8s.io/v1.23.1/kubernetes-server-linux-amd64.tar.gz

并解压到/root/kubernetes目录下

master集群

使用单节点,只要成功部署这三个服务即可,生产环境一般都会要求高可用,那么针对master节点也需要做成集聚的方式有很多中:kube-nginxkeepalived+haproxy, 这里选择keepalived+haproxy的方式。

安装软件

在所有master节点上执行如下命令:

apt install keepalived haproxy

配置haproxy

修改/etc/haproxy/haproxy.cfg:

global
    log /dev/log  local0 warning
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

   stats socket /var/lib/haproxy/stats

defaults
  log global
  option  httplog
  option  dontlognull
        timeout connect 5000
        timeout client 50000
        timeout server 50000

frontend kube-apiserver
  bind *:16443
  mode tcp
  option tcplog
  default_backend kube-apiserver

backend kube-apiserver
    mode tcp
    option tcplog
    option tcp-check
    balance roundrobin
    default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
    server kube-apiserver-1 172.16.42.144:6443 check # Replace the IP address with your own.
    server kube-apiserver-2 172.16.42.145:6443 check # Replace the IP address with your own.
    server kube-apiserver-3 172.16.42.146:6443 check # Replace the IP address with your own.

然后启动服务

systemctl enable haproxy.service
systemctl start haproxy.service

配置keepalived

修改/etc/keepalived/keepalived.conf

global_defs {
   router_id LVS_DEVEL
   script_user root
   enable_script_security
}
vrrp_script chk_apiserver {
   script "/etc/keepalived/check_apiserver.sh"
   interval 5
   weight -5
   fall 2
   rise 1 #检测一次成功,则认为在线
}
vrrp_instance VI_1 {
   state BACKUP
   nopreempt
   interface ens33
   mcast_src_ip 172.16.42.144
   virtual_router_id 51
   priority 100
   advert_int 2
   authentication {
       auth_type PASS
       auth_pass K8SHA_KA_AUTH
   }
   virtual_ipaddress {
       172.16.42.143
   }
   track_script {
      chk_apiserver
   }
}

其中interface 需要使用ip addr查看网卡名称

mcast_src_ip 是自己本地ip

virtual_ipaddress 是自定义的虚拟ip

编写check_apiserver.sh ,该文件在/etc/keepalive目录下

#!/bin/bash
err=0
for k in $(seq 1 3)
do
   check_code=$(pgrep haproxy)
   if [[ $check_code == "" ]]; then
       err=$(expr $err + 1)
       sleep 1
       continue
   else
       err=0
       break
   fi
done
​
if [[ $err != "0" ]]; then
   echo "systemctl stop keepalived"
   /usr/bin/systemctl stop keepalived
   exit 1
else
   exit 0
fi
chomd a+x check_apiserver.sh

然后启动服务

systemctl enable keepalived.service
systemctl start keepalived.service

验证

使用ip addr 查看:

可以看到自定义的虚拟ip

kubectl

kubectl是查询kubernetes的命令行工具,后面很多查询的指令都要通过这这个工具,因此,我们需要对该工具进行一下配置,kubectl默认是读取/root/.kube/configkubeconfig文件中的配置。

创建证书

admin-csr.json内容:

{
    "CN": "admin",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [],
    "names": [
        {
            "C": "CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "system:masters",
            "OU": "System"
        }
    ]
}

然后使用cfssl生成证书

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

并把证书下发到master节点的/etc/kubernetes/certs目录下

创建kubeconfig

kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/certs/ca.pem --embed-certs=true --server=htt
ps://172.16.42.143:16443 --kubeconfig=/root/.kube/config

kubectl config set-credentials admin --client-certificate=/etc/kubernetes/certs/admin.pem --client-key=/etc/kubernetes/cer
ts/admin-key.pem --embed-certs=true --kubeconfig=/root/.kube/config

kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=/root/.kube/config

kubectl config use-context kubernetes --kubeconfig=/root/.kube/config

然后把config分发给其他的master节点

kube-apiserver

创建证书

kube-apiserver-csr.json内容:

{
    "CN":"kubernetes",
    "key":{
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
        "127.0.0.1",
        "172.16.42.143",
        "172.16.42.144",
        "172.16.42.145",
        "172.16.42.146",
      	"10.254.0.1",
        "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
    ],
    "names": [
        {
            "C": "CN",
            "ST": "JiangSu",
            "L":"SuZhou",
            "O": "k8s",
            "OU": "System"
        }
    ]
}

这里的10.254.0.1kube-apiserver启动service中的service-cluster-ip-range参数的一个ip

使用cfssl生成证书

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-apiserver-csr.json | cfssljson -bare kube-apiserver

生成kube-apiserver的证书,并分发到master节点的/etc/kubernetes/certs目录下

创建审计文件

为什么需要审计文件:审计

创建audit-policy.yaml文件

apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
rules:
  # The following requests were manually identified as high-volume and low-risk, so drop them.
  - level: None
    resources:
      - group: ""
        resources:
          - endpoints
          - services
          - services/status
    users:
      - 'system:kube-proxy'
    verbs:
      - watch

  - level: None
    resources:
      - group: ""
        resources:
          - nodes
          - nodes/status
    userGroups:
      - 'system:nodes'
    verbs:
      - get

  - level: None
    namespaces:
      - kube-system
    resources:
      - group: ""
        resources:
          - endpoints
    users:
      - 'system:kube-controller-manager'
      - 'system:kube-scheduler'
      - 'system:serviceaccount:kube-system:endpoint-controller'
    verbs:
      - get
      - update

  - level: None
    resources:
      - group: ""
        resources:
          - namespaces
          - namespaces/status
          - namespaces/finalize
    users:
      - 'system:apiserver'
    verbs:
      - get

  # Don't log HPA fetching metrics.
  - level: None
    resources:
      - group: metrics.k8s.io
    users:
      - 'system:kube-controller-manager'
    verbs:
      - get
      - list

  # Don't log these read-only URLs.
  - level: None
    nonResourceURLs:
      - '/healthz*'
      - /version
      - '/swagger*'

  # Don't log events requests.
  - level: None
    resources:
      - group: ""
        resources:
          - events

  # node and pod status calls from nodes are high-volume and can be large, don't log responses
  # for expected updates from nodes
  - level: Request
    omitStages:
      - RequestReceived
    resources:
      - group: ""
        resources:
          - nodes/status
          - pods/status
    users:
      - kubelet
      - 'system:node-problem-detector'
      - 'system:serviceaccount:kube-system:node-problem-detector'
    verbs:
      - update
      - patch

  - level: Request
    omitStages:
      - RequestReceived
    resources:
      - group: ""
        resources:
          - nodes/status
          - pods/status
    userGroups:
      - 'system:nodes'
    verbs:
      - update
      - patch

  # deletecollection calls can be large, don't log responses for expected namespace deletions
  - level: Request
    omitStages:
      - RequestReceived
    users:
      - 'system:serviceaccount:kube-system:namespace-controller'
    verbs:
      - deletecollection

  # Secrets, ConfigMaps, and TokenReviews can contain sensitive & binary data,
  # so only log at the Metadata level.
  - level: Metadata
    omitStages:
      - RequestReceived
    resources:
      - group: ""
        resources:
          - secrets
          - configmaps
      - group: authentication.k8s.io
        resources:
          - tokenreviews
  # Get repsonses can be large; skip them.
  - level: Request
    omitStages:
      - RequestReceived
    resources:
      - group: ""
      - group: admissionregistration.k8s.io
      - group: apiextensions.k8s.io
      - group: apiregistration.k8s.io
      - group: apps
      - group: authentication.k8s.io
      - group: authorization.k8s.io
      - group: autoscaling
      - group: batch
      - group: certificates.k8s.io
      - group: extensions
      - group: metrics.k8s.io
      - group: networking.k8s.io
      - group: policy
      - group: rbac.authorization.k8s.io
      - group: scheduling.k8s.io
      - group: settings.k8s.io
      - group: storage.k8s.io
    verbs:
      - get
      - list
      - watch

  # Default level for known APIs
  - level: RequestResponse
    omitStages:
      - RequestReceived
    resources:
      - group: ""
      - group: admissionregistration.k8s.io
      - group: apiextensions.k8s.io
      - group: apiregistration.k8s.io
      - group: apps
      - group: authentication.k8s.io
      - group: authorization.k8s.io
      - group: autoscaling
      - group: batch
      - group: certificates.k8s.io
      - group: extensions
      - group: metrics.k8s.io
      - group: networking.k8s.io
      - group: policy
      - group: rbac.authorization.k8s.io
      - group: scheduling.k8s.io
      - group: settings.k8s.io
      - group: storage.k8s.io

  # Default level for all other requests.
  - level: Metadata
    omitStages:
      - RequestReceived

该文件分发到/etc/kubernetes/yaml文件夹下

创建加密配置文件

创建encryption-config.yaml文件:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    providers:
    - identity: {}
    - aescbc:
        keys:
        - name: key1
          secret: vlAJwUSzdHBp6RKQ+NKZUIbPTyXHXuHUtd8i4+iz3Fg=

​ 其中secret的内容需要使用head -c 32 /dev/urandom | base64来进行生成。把该文件也分发到/etc/kubernetes/yaml文件夹中

创建service文件

创建kube-apiserver.service文件

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

[Service]
ExecStart=/root/kubernetes/server/bin/kube-apiserver \
  --advertise-address=172.16.42.144 \
  --default-not-ready-toleration-seconds=360 \
  --default-unreachable-toleration-seconds=360 \
  --max-mutating-requests-inflight=2000 \
  --max-requests-inflight=4000 \
  --default-watch-cache-size=200 \
  --delete-collection-workers=2 \
  --encryption-provider-config=/etc/kubernetes/yaml/encryption-config.yaml \
  --etcd-cafile=/etc/kubernetes/certs/ca.pem \
  --etcd-certfile=/etc/kubernetes/certs/etcd.pem \
  --etcd-keyfile=/etc/kubernetes/certs/etcd-key.pem \
  --etcd-servers="https://172.16.42.144:2379,https://172.16.42.145:2379,https://172.16.42.146:2379" \
  --bind-address=172.16.42.144 \
  --secure-port=6443 \
  --tls-cert-file=/etc/kubernetes/certs/kube-apiserver.pem \
  --tls-private-key-file=/etc/kubernetes/certs/kube-apiserver-key.pem \
  --insecure-port=0 \
  --audit-log-maxage=15 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-truncate-enabled \
  --audit-log-path=/var/log/kube-apiserver/audit.log \
  --audit-policy-file=/etc/kubernetes/yaml/audit-policy.yaml \
  --profiling \
  --anonymous-auth=false \
  --client-ca-file=/etc/kubernetes/certs/ca.pem \
  --enable-bootstrap-token-auth \
  --requestheader-allowed-names="aggregator" \
  --requestheader-client-ca-file=/etc/kubernetes/certs/ca.pem \
  --requestheader-extra-headers-prefix="X-Remote-Extra-" \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --service-account-key-file=/etc/kubernetes/certs/ca.pem \
    --service-account-signing-key-file=/etc/kubernetes/certs/ca-key.pem \
    --service-account-issuer=api \
    --api-audiences=kubernetes \
  --authorization-mode=Node,RBAC \
  --runtime-config=api/all=true \
  --enable-admission-plugins=NodeRestriction \
  --allow-privileged=true \
  --apiserver-count=3 \
  --event-ttl=168h \
  --kubelet-certificate-authority=/etc/kubernetes/certs/ca.pem \
  --kubelet-client-certificate=/etc/kubernetes/certs/kube-apiserver.pem \
  --kubelet-client-key=/etc/kubernetes/certs/kube-apiserver-key.pem \
  --kubelet-timeout=10s \
  --service-cluster-ip-range="10.254.0.0/16" \
  --service-node-port-range="30000-32767" \
  --logtostderr=true \
  --v=2
Restart=on-failure
RestartSec=10
Type=notify
LimitNOFILE=65536

[Install]
zWantedBy=multi-user.target

这里需要使用mkdir -p /var/log/kube-apiserver创建一下日志存放的文件夹。

启动kube-apiserver

systemctl daemon-reload
systemctl enable kube-apiserver.sevice
systemctl start kube-apiserver.servic

验证

systemctl status kube-apiserver.service

看到如下信息,则表示启动成功:

通过curl命令查看是否每个节点都启动成功,以及haproxy是否成功

kube-controller-manager

创建证书

先创建kube-controller-manager-csr.json:

{
    "CN": "system:kube-controller-manager",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
        "127.0.0.1",
        "172.16.42.144",
        "172.16.42.145",
        "172.16.42.146"
    ],
    "names": [
        {
            "C": "CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "system:kube-controller-manager",
            "OU": "System"    
        }
    ]
}

这里需要主要,CNO里面的内容是固定的。

然后使用cfssl生成证书

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager

创建kubeconfig

master节点上操作

kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/certs/ca.pem --embed-certs=true --server=https://172.16.42.143:16443 --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

kubectl config set-credentials system:kube-controller-manager --client-certificate=/etc/kubernetes/certs/kube-controller-manager.pem --client-key=/etc/kubernetes/certs/kube-controller-manager-key.pem --embed-certs=true --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

kubectl config set-context system:kube-controller-manager --cluster=kubernetes --user=system:kube-controller-manager --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

kubectl config use-context system:kube-controller-manager --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

上述4步操作会在/root/.kube目录下创建一个kube-controller-manager.kubeconfig, 把该文件分发给其他的master节点

创建service文件

创建kube-controller-manager.service文件:

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

[Service]
ExecStart=/root/kubernetes/server/bin/kube-controller-manager \
  --profiling \
  --cluster-name=kubernetes \
  --controllers=*,bootstrapsigner,tokencleaner \
  --kube-api-qps=1000 \
  --kube-api-burst=2000 \
  --leader-elect \
  --use-service-account-credentials\
  --concurrent-service-syncs=2 \
  --bind-address=172.16.42.144 \
  --secure-port=10252 \
  --tls-cert-file=/etc/kubernetes/certs/kube-controller-manager.pem \
  --tls-private-key-file=/etc/kubernetes/certs/kube-controller-manager-key.pem \
  --port=0 \
  --authentication-kubeconfig=/root/.kube/kube-controller-manager.kubeconfig \
  --client-ca-file=/etc/kubernetes/certs/ca.pem \
  --requestheader-allowed-names="aggregator" \
  --requestheader-client-ca-file=/etc/kubernetes/certs/ca.pem \
  --requestheader-extra-headers-prefix="X-Remote-Extra-" \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --authorization-kubeconfig=/root/.kube/kube-controller-manager.kubeconfig \
  --cluster-signing-cert-file=/etc/kubernetes/certs/ca.pem \
  --cluster-signing-key-file=/etc/kubernetes/certs/ca-key.pem \
  --experimental-cluster-signing-duration=876000h \
  --horizontal-pod-autoscaler-sync-period=10s \
  --concurrent-deployment-syncs=10 \
  --concurrent-gc-syncs=30 \
  --node-cidr-mask-size=24 \
  --service-cluster-ip-range="10.254.0.0/16" \
  --pod-eviction-timeout=6m \
  --terminated-pod-gc-threshold=10000 \
  --root-ca-file=/etc/kubernetes/certs/ca.pem \
  --service-account-private-key-file=/etc/kubernetes/certs/ca-key.pem \
  --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig \
  --logtostderr=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

把该文件分发给其他的master节点,然后修改对应的bind-address

启动kube-controller-manager

systemctl enable kube-controller-manager.service

systemctl start kube-controller-manager.service

kube-scheduler

创建证书

创建kube-scheduler-csr.json

{
    "CN":"system:kube-scheduler",
    "hosts": [
        "127.0.0.1",
        "172.16.42.144",
        "172.16.42.145",
        "172.16.42.146"
    ],
    "key": {
        "algo": "rsa",
        "size":  2048
    },
    "names":[
        {
            "C": "CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "system:kube-scheduler",
            "OU": "System"
        }
    ]
}

然后使用cfssl创建证书

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler

把证书分发给所有master节点

创建kubeconfig

kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/certs/ca.pem --embed-certs=true --server=https://172.16.42.143:16443 --kubeconfig=/root/.kube/kube-scheduler.kubeconfig

kubectl config set-credentials system:kube-scheduler --client-certificate=/etc/kubernetes/certs/kube-scheduler.pem --clien
t-key=/etc/kubernetes/certs/kube-scheduler-key.pem --embed-certs=true --kubeconfig=/root/.kube/kube-scheduler.kubeconfig

kubectl config set-context system:kube-scheduler --cluster=kubernetes --user=system:kube-scheduler --kubeconfig=/root/.kube/kube-scheduler.kubeconfig

kubectl config use-context system:kube-scheduler --kubeconfig=/root/.kube/kube-scheduler.kubeconfig

把所有的kube-scheduler.kubeconfig分发到其他的master节点

创建配置文件

创建kube-scheduler.yaml配置文件,并把该文件放在/etc/kubernetes/yaml目录下

apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
clientConnection:
  burst: 200
  kubeconfig: "/root/.kube/kube-scheduler.kubeconfig"
  qps: 100
enableContentionProfiling: false
enableProfiling: true
leaderElection:
  leaderElect: true

把该配置文件分发到其余的master节点,并修改相应的ip

创建service文件

新建kube-scheduler.service文件

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

[Service]
ExecStart=/root/kubernetes/server/bin/kube-scheduler \
  --config=/etc/kubernetes/yaml/kube-scheduler.yaml \
  --bind-address=172.16.42.144 \
  --secure-port=10259 \
  --port=0 \
  --tls-cert-file=/etc/kubernetes/certs/kube-scheduler.pem \
  --tls-private-key-file=/etc/kubernetes/certs/kube-scheduler-key.pem \
  --authentication-kubeconfig=/root/.kube/kube-scheduler.kubeconfig \
  --client-ca-file=/etc/kubernetes/certs/ca.pem \
  --requestheader-allowed-names="" \
  --requestheader-client-ca-file=/etc/kubernetes/certs/ca.pem \
  --requestheader-extra-headers-prefix="X-Remote-Extra-" \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --authorization-kubeconfig=/root/.kube/kube-scheduler.kubeconfig \
  --logtostderr=true \
  --v=2
Restart=always
RestartSec=5
StartLimitInterval=0

[Install]
WantedBy=multi-user.target

把该service文件分发到其他master节点,并修改bind-address

启动kube-scheduler

systemctl enable kube-scheduler

systemctl start kube-scheduler

Node节点

组成

node节点主要由kubeletkube-proxy组成

wget https://dl.k8s.io/v1.23.1/kubernetes-node-linux-amd64.tar.gz

并解压到/root/kubernetes目录下

containerd

在这里没有使用docker,而是选择containerd

下载containerd

wget https://github.com/containerd/containerd/releases/download/v1.5.7/containerd-1.5.7-linux-amd64.tar.gz
VERSION="v1.22.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
wget https://github.com/containernetworking/plugins/releases/download/v1.0.1/cni-plugins-linux-amd64-v1.0.1.tgz

apt install runc

所有node节点都需要安装, 并把所有压缩文件中的内容都解压到/etc/kubernetes/bin目录下

创建containerd配置文件

先使用containerd config default > /etc/containerd/config.toml生成默认的配置文件。

然后修改plugins."io.containerd.grpc.v1.cri"节点下的sandbox_image,默认的image 国内无法下载, 并且修改plugins."io.containerd.grpc.v1.cri".cnibin_dir

  [plugins."io.containerd.grpc.v1.cri"]
    disable_apparmor = false
    disable_cgroup = false
    disable_hugetlb_controller = true
    disable_proc_mount = false
    disable_tcp_service = true
    enable_selinux = false
    enable_tls_streaming = false
    ignore_image_defined_volumes = false
    max_concurrent_downloads = 3
    max_container_log_line_size = 16384
    netns_mounts_under_state_dir = false
    restrict_oom_score_adj = false
    sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5"
    selinux_category_range = 1024
    stats_collect_period = 10
    stream_idle_timeout = "4h0m0s"
    stream_server_address = "127.0.0.1"
    stream_server_port = "0"
    systemd_cgroup = false
    tolerate_missing_hugetlb_controller = true
    unset_seccomp_profile = ""

    [plugins."io.containerd.grpc.v1.cri".cni]
      bin_dir = "/etc/kubernetes/bin"
      conf_dir = "/etc/cni/net.d"
      conf_template = ""
      max_conf_num = 1

创建service

创建containerd.service

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
Environment="PATH=/etc/kubernetes/bin:/bin:/sbin:/usr/bin:/usr/sbin"
ExecStartPre=/sbin/modprobe overlay
ExecStart=/etc/kubernetes/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target

并分发给所有node节点

启动containerd

systemctl enable containerd.service
systemctl start containerd.service

修改crictl配置

crictl是一个兼容CRI容器运行时的命令行工具,提供类似于docker命令的功能,默认是使用unix:///var/run/dockershim.sock,我们需要调整为unix:///run/containerd/containerd.sock

创建crictl.yaml的文件,并保存到/etc目录下

runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

kubelet

创建kubelet bootstrap kubeconfig

需要为所有的kubelet客户端创建一个token

kubeadm token create --description kubelet-bootstrap-token --groups system:bootstrappers:k8s-01 --kubeconfig /root/.kube/config
## 保留该token eg: 7qwqwk.frwmxy5o2s0irio3

kubectl config set-cluster kubernetes  --certificate-authority=/etc/kubernetes/certs/ca.pem --embed-certs=true --server=https://172.16.42.143:16443 --kubeconfig=/root/.kube/kubelet-bootstrap-k8s-01.kubeconfig

kubectl config set-credentials kubelet-bootstrap  --token=7qwqwk.frwmxy5o2s0irio3 --kubeconfig=/root/.kube/kubelet-bootstrap-k8s-01.kubeconfig 

kubectl config set-context default --cluster=kubernetes --user=kubelet-bootstrap --kubeconfig=/root/.kube/kubelet-bootstrap-k8s-01.kubeconfig

kubectl config use-context default --kubeconfig=/root/.kube/kubelet-bootstrap-k8s-01.kubeconfig

重复执行上述脚本,然后修改kubeadm --groupskubectl --kubeconfigkubectl --token中的内容。然后把对应的文件分发到对应的服务器的/root/.kube目录下,并重新命名为kubelet-bootstrap.kubeconfig

创建kubelet的参数配置

创建kubelet-config.yaml,并存放在/etc/kubernetes/conf目录下

kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: "172.16.42.144"
syncFrequency: 1m
fileCheckFrequency: 20s
httpCheckFrequency: 20s
port: 10250
readOnlyPort: 0
rotateCertificates: true
serverTLSBootstrap: true
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/etc/kubernetes/certs/ca.pem"
authorization:
  mode: Webhook
registryPullQPS: 0
registryBurst: 20
eventRecordQPS: 0
eventBurst: 20
enableDebuggingHandlers: true
enableContentionProfiling: true
healthzPort: 10248
healthzBindAddress: "172.16.42.144"
clusterDomain: "cluster.local"
clusterDNS:
  - "10.254.0.2"
nodeStatusUpdateFrequency: 10s
nodeStatusReportFrequency: 1m
imageMinimumGCAge: 2m
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
volumeStatsAggPeriod: 1m
cgroupsPerQOS: true
cgroupDriver: cgroupfs 
runtimeRequestTimeout: 10m
hairpinMode: promiscuous-bridge
maxPods: 220
podCIDR: "172.30.0.0/16"
podPidsLimit: -1
resolvConf: /etc/resolv.conf
maxOpenFiles: 1000000
kubeAPIQPS: 1000
kubeAPIBurst: 2000
serializeImagePulls: false
evictionHard:
  memory.available:  "100Mi"
  nodefs.available:  "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"
evictionSoft: {}
enableControllerAttachDetach: true
failSwapOn: true
containerLogMaxSize: 20Mi
containerLogMaxFiles: 10
systemReserved: {}
kubeReserved: {}
enforceNodeAllocatable: ["pods"]

分发给其余node并修改healthzBindAddressaddress为本机ip

创建service

创建kubelet.service

[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/root/kubernetes/node/bin/kubelet \
  --bootstrap-kubeconfig=/root/.kube/kubelet-bootstrap.kubeconfig \
  --cert-dir=/etc/kubernetes/certs \
  --cni-conf-dir=/etc/cni/net.d \
  --container-runtime=remote \
  --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \
  --kubeconfig=/root/.kube/kubelet.kubeconfig \
  --config=/etc/kubernetes/yaml/kubelet-config.yaml \
  --network-plugin=cni \
  --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=always
RestartSec=5
StartLimitInterval=0

[Install]
WantedBy=multi-user.target

授予kube-apiserver访问kubelet API 权限

kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes

这里的--userapiserver证书中的CN

Bootstrap Token Auth

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers

启动kubelet

systemctl enable kubelet.service
systemctl start kubelet.service

approve证书

kubectl get csr | grep Pending | awk '{print $1}' | xargs kubectl certificate approve

kubelet 服务启动之后,会向master节点,发送证书请求,需要在master节点批准这些证书请求。

通过kubectl get csr可以看到当前为批准的证书请求

验证

完成上述操作之后使用kubectl get nodes查看当前节点状态:

kube-proxy

创建证书

创建kube-proxy-csr.json

{
    "CN": "system:kube-proxy",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "JiangSu",
            "L": "SuZhou",
            "O": "k8s",
            "OU": "System"
        }
    ]
}

使用cfssl创建证书

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

然后把创建的证书分发到node节点的/etc/kubernetes/certs目录下

创建kubeconfig

创建kube-proxy.kubeconfig

kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/certs/ca.pem --embed-certs=true --server=https://172.16.42.143:16443 --kubeconfig=/root/.kube/kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy --client-certificate=/etc/kubernetes/certs/kube-proxy.pem --client-key=/etc/kubernetes/certs/kube-proxy-key.pem --embed-certs=true --kubeconfig=/root/.kube/kube-proxy.kubeconfig

kubectl config set-context default --cluster=kubernetes --user=kube-proxy --kubeconfig=/root/.kube/kube-proxy.kubeconfig

kubectl config use-context default --kubeconfig=/root/.kube/kube-proxy.kubeconfig

然后把kube-proxy.kubeconfig分发到其他node节点的/root/.kube目录下

创建kube-proxy配置文件

创建kube-proxy.yaml文件,该文件在/etc/kubernetes/yaml目录下

kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  burst: 200
  kubeconfig: /root/.kube/kube-proxy.kubeconfig
  qps: 100
bindAddress: 172.16.42.144
healthzBindAddress: 172.16.42.140:10256
metricsBindAddress: 172.16.42.140:10249
enableProfiling: true
clusterCIDR: 172.30.0.0/16
mode: "ipvs"

把该文件分发给其他的node节点。并修改对应的bindAddresshealthzBindAddressmetricsBindAddress

创建service

创建kube-proxy.service

[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/root/kubernetes/node/bin/kube-proxy \
  --config=/etc/kubernetes/yaml/kube-proxy-config.yaml \
  --logtostderr=true \
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

然后把该文件分发给其他node节点

启动kube-proxy

systemctl enable kube-proxy.service
systemctl start kube-proxy.service

calico

完成上述操作之后,kubernetes的安装基本完成了,但如果要正常操作,还需要安装网络插件,这里选择使用calico

下载calico

wget https://github.com/projectcalico/calico/releases/download/v3.21.2/release-v3.21.2.tgz

然后解压并修改k8s-manifests/calico.yaml

----
- name: CALICO_IPV4POOL_CIDR
  value: "172.30.0.0/16"
- name: IP_AUTODETECTION_METHOD  
  value: "interface=ens.*"
            # Disable file logging so `kubectl logs` works.
- name: CALICO_DISABLE_FILE_LOGGING
  value: "true"
----
----
 - name: cni-bin-dir
          hostPath:
            path: /etc/kubernetes/bin
----

搜索CALICO_DISABLE_FILE_LOGGING, 在上面添加CALICO_IPV4POOL_CIDRIP_AUTODETECTION_METHOD,其中IP_AUTODETECTION_METHOD中的ens.*需要根据机器的网卡名称来修改

应用

kubectl apply -f calico.yaml

验证

等待所有镜像拉取并启动成功,输入kubectl get nodes

所有的node节点的状态都是Ready,则表示网络插件应用成功。

创建一个应用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.17
        ports:
        - containerPort: 80

保存并命名为my-nginx.yaml,下发到其中一个master。然后使用

kubectl create -f my-nginx.yaml
kubectl expose deployment my-nginx

等待一段时间之后

 kubectl get svc,deployment -o wide

可以看到

参考

  1. follow-me-install-kubernetes-cluster
  2. Kubernetes 1.22.1 高可用二进制部署
  3. 使用 kubeconfig 文件组织集群访问
  4. kube-apiserver
  5. kube-controller-manager
  6. kube-proxy
  7. kube-scheduler
  8. kubelet