K8S丨部署丨二进制部署Kubernetes

1. 环境说明

1.1 前置知识点

生产环境可部署Kubernetes集群的两种方式

  • 目前生产部署Kubernetes集群主要有两种方式:

    • kubeadm
      Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。
      官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

    • 二进制包
      从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。

Kubeadm降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署Kubernetes集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。

之前发布的二进制部署因为没有写rabc授权和master节点过于空闲,于是重新写了这篇文章。

1.2 服务器规划

  • k8s-master1&node1192.168.1.30
    • kube-apiserver
    • kube-controller-manager
    • kube-scheduler
    • kubelet
    • kube-proxy
    • docker
    • etcd
  • k8s-master2&node2192.168.1.31
    • kube-apiserver
    • kube-controller-manager
    • kube-scheduler
    • kubelet
    • kube-proxy
    • docker
    • etcd
  • k8s-node3192.168.1.32
    • kubelet
    • kube-proxy
    • docker
    • etcd
  • k8s-node4192.168.1.33
    • kubelet
    • kube-proxy
    • docker
  • k8s-node5192.168.1.34
    • kubelet
    • kube-proxy
    • docker
  • Load Balancer-Master192.168.1.51 ————|
    • Nginx L4—————————————-|— 192.168.1.50(VIP)
  • Load Balancer-Backup192.168.1.52 ————|
    • Nginx L4
  • harbor192.168.1.60
    • harbor
  • 子网:192.168.1.0/24
  • 网关:192.168.1.1

1.2.1 Kubernetes拓扑图

1.2.1Kubernetes拓扑图.png

1.2.2 单Master架构图

1.2.2单Master架构图.png

1.3 系统环境初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# centos7阿里源
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

# epel源
mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup
mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld

# 关闭selinux # 重启生效 或 setenforce 0
sed -i.bak 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

# 关闭swap
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 根据规划设置主机名
hostnamectl set-hostname <hostname>

# 添加hosts
cat >> /etc/hosts << EOF
192.168.1.30 k8s-master1
192.168.1.31 k8s-master2
192.168.1.32 k8s-node3
192.168.1.33 k8s-node4
192.168.1.34 k8s-node5
EOF

# 时间同步定时任务
yum install ntpdate -y
echo '# time sync by jeremy at 2020-11-10' >>/var/spool/cron/root
echo '* */6 * * * /usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1' >>/var/spool/cron/root
crontab -l

# 内核优化参数
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_fin_timeout = 2
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.ip_local_port_range = 4000 65000
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_max_orphans = 16384
EOF
sysctl -p

# 必要工具
yum -y install wget net-tools telnet tree nmap sysstat lrzsz dos2unix bind-utils

# 重启(建议)
reboot

PS:可以升级一下CentOS的Linux内核,CentOS自带的Linux为3.10,可以升级到长期支持版本5.4。(容器技术会依靠于Linux内核)
这篇文章是后写的,所以想到内核时已经部署好了,当然部署好了也可以升级内核,实测在node5升级了5.4内核,暂时没有出任何问题,后续继续查看。


2. 创建TLS证书及密钥

Kubernetes系统的各组件需要使用 TLS 证书对通信进行加密,本文档使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Authority (CA) 和其它证书;

本实例的证书创建都集中在本章节

2.1 证书说明

  • 集群TLS认证需要的证书及密钥如下:
    • ca.pem
    • ca-key.pem
    • etcd.pem
    • etcd-key.pem
    • apiserver.pem
    • apiserver-key.pem
    • client.pem(本实例用Bootstrapping,没用该证书)
    • client-key.pem(本实例用Bootstrapping,没用该证书)
    • kubelet.pem(本实例用Bootstrapping,没用该证书)
    • kubelet-key.pem(本实例用Bootstrapping,没用该证书)
    • kube-proxy.pem
    • kube-proxy-key.pem

2.2 安装证书制作工具-CFSSL

1
2
3
4
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl 
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssl-json
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo
chmod +x /usr/local/bin/cfssl*
  • 关于CFSSL
  • cfssl:证书签发的主要工具
  • cfssl-json:将cfssl生成的整数(json格式)变为文件承载式证书
  • cfssl-certinfo:验证证书的信息

2.3 创建CA证书

  1. CA配置文件

在harbor主机上制作证书,然后发放
mkdir -p cert && cd cert
过期时间设置成了 87600h(十年)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"peer": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF

字段说明:
ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;
signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;
server auth:表示client可以用该 CA 对server提供的证书进行验证;
client auth:表示server可以用该 CA 对client提供的证书进行验证;
87600h:十年

  1. CA证书申请表(生成CA自签名请求)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    cat > ca-csr.json << EOF
    {
    "CN": "k8s-ca",
    "hosts": [ ],
    "key": {
    "algo": "rsa",
    "size": 2048
    },
    "names": [
    {
    "C": "CN",
    "ST": "BeiJing",
    "L": "BeiJing",
    "O": "K8s",
    "OU": "System"
    }
    ],
    "ca": {
    "expiry": "87600h"
    }
    }
    EOF

字段说明:

  • CN:浏览器使用该字段验证网站是否合法,一般写的是域名,非常重要
  • C:国家
  • ST:州/省
  • L:地区/城市
  • O:组织名称/公司名称
  • OU:组织单位名称,公司部门
  1. 生成
    1
    2
    3
    cfssl gencert -initca ca-csr.json | cfssl-json -bare ca

    # 如果命令执行错误,则需要检查json文件

2.4 创建etcd证书

  1. etcd证书申请表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    cat > etcd-csr.json << EOF
    {
    "CN": "k8s-etcd",
    "hosts": [
    "127.0.0.1",
    "192.168.1.30",
    "192.168.1.31",
    "192.168.1.32",
    "192.168.1.33",
    "192.168.1.34"
    ],
    "key": {
    "algo": "rsa",
    "size": 2048
    },
    "names": [
    {
    "C": "CN",
    "ST": "BeiJing",
    "L": "BeiJing",
    "O": "k8s",
    "OU": "System"
    }
    ]
    }
    EOF

注:上述文件hosts字段中IP为所有etcd节点的集群内部通信IP,一个都不能少!为了方便后期扩容可以多写几个预留的IP。

  1. 生成
    1
    2
    3
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer etcd-csr.json | cfssl-json -bare etcd

    # 如果命令执行错误,则需要检查json文件

注:因为是对等证书,需要指定hosts(即只能在指定的IP上使用);hosts指定的IP均为etcd各节点的IP
参数说明:
-ca=ca.pem # CA证书
-ca-key=ca-key.pem # CA证书
-config=ca-config.json # CA配置文件
-profile=peer # 这个peer是指ca-config.json文件里的profiles
etcd-csr.json # etcd配置文件

2.5 创建apiserver证书

  1. 证书申请表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
cat > apiserver-csr.json << EOF
{
"CN": "k8s-apiserver",
"hosts": [
"192.168.80.1",
"127.0.0.1",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local",
"192.168.1.30",
"192.168.1.31",
"192.168.1.32",
"192.168.1.33",
"192.168.1.34",
"192.168.1.35",
"192.168.1.36",
"192.168.1.37",
"192.168.1.38",
"192.168.1.39",
"192.168.1.50",
"192.168.1.51",
"192.168.1.52",
"192.168.1.60"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
  • 字段说明:
  • hosts:指定授权使用该证书的 IP 或域名列表,这里列出了 VIP 、apiserver节点 IP、kubernetes 服务 IP 和域名;
  • 域名最后字符不能是 kubernetes.default.svc.cluster.local. (如为kubernetes.default.svc.cluster.local. ),否则解析时失败,提示: x509:cannot parse dnsName "kubernetes.default.svc.cluster.local." ;如果使用非 cluster.local 域名,如 jeremy.com ,则需要修改域名列表中的最后两个域名为: kubernetes.default.svc.jeremykubernetes.default.svc.jeremy.com
  • kubernetes 服务 IP 是 apiserver 自动创建的,一般是 --service-cluster-ip-range 参数指定的网段的第一个IP,如:192.168.80.1,可以通过如下命令获取:kubectl get svc kubernetes
  1. 生成
    1
    2
    3
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer apiserver-csr.json | cfssl-json -bare apiserver

    # 如果命令执行错误,则需要检查json文件

2.6 创建kube-proxy证书

  1. 证书申请表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    cat > kube-proxy-csr.json << EOF
    {
    "CN": "system:kube-proxy",
    "hosts": [],
    "key": {
    "algo": "rsa",
    "size": 2048
    },
    "names": [
    {
    "C": "CN",
    "ST": "BeiJing",
    "L": "BeiJing",
    "O": "k8s",
    "OU": "System"
    }
    ]
    }
    EOF
  2. 生成

    1
    2
    3
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer kube-proxy-csr.json | cfssl-json -bare kube-proxy

    # 如果命令执行错误,则需要检查json文件

3. Etcd集群部署

hostname 节点名称 IP
k8s-master1 etcd-1 192.168.1.30
k8s-master2 etcd-2 192.168.1.31
k8s-node3 etcd-3 192.168.1.32

3.1 安装

github地址

1
2
3
4
5
6
7
wget https://github.com/etcd-io/etcd/releases/download/v3.4.13/etcd-v3.4.13-linux-amd64.tar.gz

tar -xzvf etcd-v3.4.13-linux-amd64.tar.gz

mkdir /opt/etcd/{bin,conf.d,cert} -p

mv etcd-v3.4.13-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/

3.2 创建证书

  • 请看2.4 创建etcd证书

  • 拷贝到证书

    1
    scp {ca,etcd,etcd-key}.pem k8s-master1:/opt/etcd/cert

3.3 各etcd节点配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
cat > /opt/etcd/conf.d/etcd.conf << EOF
# [Member]
ETCD_NAME="etcd-1"
ETCD_DATA_DIR="/opt/etcd/data"
ETCD_LISTEN_PEER_URLS="https://192.168.1.30:2380" # 不同节点需要更改
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.30:2379" # 不同节点需要更改

# [Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.30:2380" # 不同节点需要更改
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.30:2379" # 不同节点需要更改
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.1.30:2380,etcd-2=https://192.168.1.31:2380,etcd-3=https://192.168.1.32:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-token"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

-----------------------------------

cat > /opt/etcd/conf.d/etcd.conf << EOF
# [Member]
ETCD_NAME="etcd-2"
ETCD_DATA_DIR="/opt/etcd/data"
ETCD_LISTEN_PEER_URLS="https://192.168.1.31:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.31:2379"

# [Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.31:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.31:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.1.30:2380,etcd-2=https://192.168.1.31:2380,etcd-3=https://192.168.1.32:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-token"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

------------------------------------

cat > /opt/etcd/conf.d/etcd.conf << EOF
# [Member]
ETCD_NAME="etcd-3"
ETCD_DATA_DIR="/opt/etcd/data"
ETCD_LISTEN_PEER_URLS="https://192.168.1.32:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.32:2379"

# [Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.32:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.32:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.1.30:2380,etcd-2=https://192.168.1.31:2380,etcd-3=https://192.168.1.32:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-token"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

注意:别把注释带配置文件
参数说明:
ETCD_NAME:节点名称,集群中唯一
ETCD_DATA_DIR:数据目录
ETCD_LISTEN_PEER_URLS:集群通信监听地址
ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址
ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
ETCD_INITIAL_CLUSTER:集群节点地址
ETCD_INITIAL_CLUSTER_TOKEN:集群Token
ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new是新集群,existing表示加入已有集群

3.4 systemd管理etcd

  • systemd文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    cat > /usr/lib/systemd/system/etcd.service << EOF
    [Unit]
    Description=Etcd Server
    After=network.target
    After=network-online.target
    Wants=network-online.target
    [Service]
    Type=notify
    EnvironmentFile=/opt/etcd/conf.d/etcd.conf
    ExecStart=/opt/etcd/bin/etcd \\
    --cert-file=/opt/etcd/cert/etcd.pem \\
    --key-file=/opt/etcd/cert/etcd-key.pem \\
    --peer-cert-file=/opt/etcd/cert/etcd.pem \\
    --peer-key-file=/opt/etcd/cert/etcd-key.pem \\
    --trusted-ca-file=/opt/etcd/cert/ca.pem \\
    --peer-trusted-ca-file=/opt/etcd/cert/ca.pem \\
    --log-level=info \\
    --logger=zap \\
    --log-outputs=stderr
    Restart=on-failure
    LimitNOFILE=65536
    [Install]
    WantedBy=multi-user.target
    EOF
  • 启动并设置开机启动

    1
    2
    3
    4
    systemctl daemon-reload 
    systemctl start etcd
    systemctl status etcd
    systemctl enable etcd

3.5 检查etcd集群节点健康情况

  • etcd各节点健康情况
    1
    2
    3
    4
    5
    6
    /opt/etcd/bin/etcdctl \
    --endpoints="https://192.168.1.30:2379,https://192.168.1.31:2379,https://192.168.1.32:2379" \
    --cacert=/opt/etcd/cert/ca.pem \
    --cert=/opt/etcd/cert/etcd.pem \
    --key=/opt/etcd/cert/etcd-key.pem \
    --write-out=table endpoint health
    3.5.1etcd各节点健康情况.png
  • etcd各节点状态情况
    1
    2
    3
    4
    5
    6
    /opt/etcd/bin/etcdctl \
    --endpoints="https://192.168.1.30:2379,https://192.168.1.31:2379,https://192.168.1.32:2379" \
    --cacert=/opt/etcd/cert/ca.pem \
    --cert=/opt/etcd/cert/etcd.pem \
    --key=/opt/etcd/cert/etcd-key.pem \
    --write-out=table endpoint status
    3.5.2etcd各节点状态情况.png

ps: 表格显示加--write-out=table


4. Docker部署

一般情况只有node节点才需要安装docker的,但是本次实例master节点同时也是node节点,所以也需要安装docker,所以本次实例给所有机器安装docker

4.1 下载解压二进制包

  1. 下载地址

docker-19.03.9下载地址

  1. 安装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    tar -xzvf docker-19.03.9.tgz
    mkdir -p /opt/docker/bin
    mv docker/* /opt/docker/bin

    ln -sv /opt/docker/bin/docker /usr/local/bin/
    ln -sv /opt/docker/bin/containerd /usr/local/bin/
    ln -sv /opt/docker/bin/containerd-shim /usr/local/bin/
    ln -sv /opt/docker/bin/ctr /usr/local/bin/
    ln -sv /opt/docker/bin/dockerd /usr/local/bin/
    ln -sv /opt/docker/bin/docker-init /usr/local/bin/
    ln -sv /opt/docker/bin/docker-proxy /usr/local/bin/
    ln -sv /opt/docker/bin/runc /usr/local/bin/

4.2 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p /opt/docker/data  /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"graph": "/opt/docker/data",
"storage-driver": "overlay2",
"insecure-registries": ["registry.access.redhat.com","quay.io","harbor.jeremy.cn"],
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
"bip": "172.8.30.1/24",
"exec-opts": ["native.cgroupdriver=cgroupfs"],
"live-restore": true
}
EOF

bip:172.8.x.1/24,x按照宿主机IP地址最后一位来设置
insecure-registries:需要添加你harbor的域名,不然harbor无法登录

4.3 systemd管理docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat > /usr/lib/systemd/system/docker.service << EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/opt/docker/bin/dockerd
ExecReload=/bin/kill -s HUP \$MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target
EOF

4.4 启动docker

1
2
systemctl daemon-reload && systemctl start docker
systemctl enable docker && systemctl status docker

5. Harbor部署

5.1 下载解压二进制包

  1. 下载地址

下载地址

  1. 校验

下载对应版本的检验码进行校验:
v2.1.1校验码

然后使用 md5sum -c md5sum 来查看文件内容是否正确,如果正确,会显示下面的内容。

1
2
[root@harbor opt]# md5sum -c md5sum
harbor-offline-installer-v2.1.1.tgz: OK

如果你下载是harbor-offline-installer-v2.1.1.tgz,则这个才会显示ok;
而没下载的例如:harbor-online-installer-v2.1.1.tgz,则会提示md5sum: harbor-online-installer-v2.1.1.tgz: No such file or directory

  1. 解压
1
2
3
4
5
6
7
8
tar -xzvf harbor-offline-installer-v2.1.1.tgz

harbor/harbor.v2.1.1.tar.gz
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl

5.2 配置文件

harbor.yml.tmpl 这个文件配置文件模板,可以按其格式来
去掉注释:grep -v "#" harbor.yml.tmpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
cd /opt/harbor/
vim harbor.yml

hostname: harbor.jeremy.cn
http:
port: 8080
harbor_admin_password: Harbor12345
database:
password: root123
max_idle_conns: 50
max_open_conns: 1000
data_volume: /opt/harborData
clair:
updaters_interval: 12
trivy:
ignore_unfixed: false
skip_update: false
insecure: false
jobservice:
max_job_workers: 10
notification:
webhook_job_max_retry: 10
chart:
absolute_url: disabled
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /opt/harborData/logs
_version: 2.0.0
proxy:
http_proxy:
https_proxy:
no_proxy:
components:
- core
- jobservice
- clair
- trivy

参数说明:
一般情况下,我们最少需要配置的内容如下:

  • hostname 需要配置为 127.0.0.1 之外的内容,以提供外部访问
  • https 的配置需要同时配置证书,生产环境中,如果使用 SLB 或者使用其他应用统一提供 SSL 接入,则可以删除。
  • harbor_admin_password 默认密码即可,但是初次使用登陆后台后需要修改密码。
  • data_volume 根据自己实际情况修改宿主机的文件储存地址。
  • 创建harbor数据存储目录
    1
    2
    mkdir -p /opt/harborData
    mkdir -p /opt/harborData/logs

5.3 docker-compose启动harbor

  1. 下载安装docker-compose

    1
    2
    3
    curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

    chmod +x /usr/local/bin/docker-compose
  2. 启动harbor

修改完配置之后,使用 bash install.sh 进行应用安装。

1
sh /opt/harbor/install.sh
  • docker-compose查看

5.3用docker-compose查看.png

5.4 nginx代理harbor本地端口

  1. 安装

    1
    yum install nginx -y
  2. nginx配置文件
    vim /etc/nginx/conf.d/harbor.conf

    1
    2
    3
    4
    5
    6
    7
    8
    server {
    listen 80;
    server_name harbor.jeremy.cn;
    client_max_body_size 1000m;
    location / {
    proxy_pass http://127.0.0.1:8080;
    }
    }
  3. 启动nginx

    1
    2
    3
    systemctl start nginx
    systemctl enable nginx
    systemctl status nginx
  4. 添加host记录

1
2
3
cat >> /etc/hosts << EOF
192.168.1.60 harbor.jeremy.cn
EOF
  1. 上传镜像
  • 访问http://harbor.jeremy.cn/
    5.4上传镜像-1.png

  • 添加一个public
    5.4上传镜像-2.png

  • 拉取
    docker pull nginx

1
2
3
[root@harbor harbor]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest c39a868aad02 33 hours ago 133MB
  • 打tag

    1
    docker tag c39a868aad02 harbor.jeremy.cn/public/nginx:latest
  • 登录

    1
    2
    3
    4
    5
    6
    7
    8
    [root@harbor harbor]# docker login harbor.jeremy.cn 
    Username: admin
    Password:
    WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store

    Login Succeeded

要登陆的需要在/etc/docker/daemon.json 里面的 insecure-registries 添加harbor的域名(harbor.jeremy.cn),不然无法使用http登录,https登录则需要配置中有https
如果之前的docker配置没有添加harbor的域名,则需要重新打包运行harbor,不然还是登录不了

  • 推送镜像到harbor
    1
    2
    3
    4
    5
    6
    7
    8
    [root@harbor harbor]# docker push harbor.jeremy.cn/public/nginx:latest
    The push refers to repository [harbor.jeremy.cn/public/nginx]
    7b5417cae114: Pushed
    aee208b6ccfb: Pushed
    2f57e21e4365: Pushed
    2baf69a23d7a: Pushed
    d0fe97fa8b8c: Pushed
    latest: digest: sha256:34f3f875e745861ff8a37552ed7eb4b673544d2c56c7cc58f9a9bec5b4b3530e size: 1362

6. Master节点部署

kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能:

  • 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
  • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd)。
hostname 节点名称 IP
k8s-master1 master1 192.168.1.30
k8s-master2 master2 192.168.1.31
  • k8s-master1&node1192.168.1.30
    • kube-apiserver
    • kube-controller-manager
    • kube-scheduler
    • kubelet
    • kube-proxy
    • docker
    • etcd
  • k8s-master2&node2192.168.1.31
    • kube-apiserver
    • kube-controller-manager
    • kube-scheduler
    • kubelet
    • kube-proxy
    • docker

6.1 kube-apiserver部署

  1. 下载地址

kubernetes GitHub地址

  • 从Github下载二进制文件
    1
    2
    3
    下载地址: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md#v1183

    注:打开链接你会发现里面有很多包,下载一个server包就够了,包含了Master和Worker Node二进制文件。

1.18.10版本wget https://storage.googleapis.com/kubernetes-release/release/v1.18.10/kubernetes-server-linux-amd64.tar.gz

  1. 解压和创建文件夹

分别在两台master上下载kubernetes-server-linux-amd64.tar.gz

1
2
3
tar -xzvf kubernetes-server-linux-amd64.tar.gz -C /opt

mkdir /opt/kubernetes/server/{cert,conf.d,logs}

/opt/kubernetes/server/cert:存放证书
/opt/kubernetes/server/conf:存放启动配置文件

  1. 创建证书
  • 查看 2.5 创建apiserver证书
  1. 拷贝证书
    1
    2
    3
    4
    scp /root/cert/{ca.pem,ca-key.pem,apiserver.pem,apiserver-key.pem,etcd.pem,etcd-key.pem}  k8s-master1:/opt/kubernetes/server/cert

    ls server/cert/
    >> apiserver-key.pem apiserver.pem ca-key.pem ca.pem etcd-key.pem etcd.pem

注意私钥文件属性600

  1. 创建配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cat > /opt/kubernetes/server/conf.d/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--service-cluster-ip-range=192.168.80.0/24 \\
--service-node-port-range=30000-45535 \\
--apiserver-count=2 \\
--advertise-address=192.168.1.30 \\
--bind-address=192.168.1.30 \\
--secure-port=6443 \\
--authorization-mode=RBAC,Node \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--allow-privileged=true \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/server/conf.d/token.csv \\
--etcd-cafile=/opt/kubernetes/server/cert/ca.pem \\
--etcd-certfile=/opt/kubernetes/server/cert/etcd.pem \\
--etcd-keyfile=/opt/kubernetes/server/cert/etcd-key.pem \\
--etcd-servers=https://192.168.1.30:2379,https://192.168.1.31:2379,https://192.168.1.32:2379 \\
--kubelet-client-certificate=/opt/kubernetes/server/cert/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/server/cert/apiserver-key.pem \\
--tls-cert-file=/opt/kubernetes/server/cert/apiserver.pem \\
--tls-private-key-file=/opt/kubernetes/server/cert/apiserver-key.pem \\
--service-account-key-file=/opt/kubernetes/server/cert/ca-key.pem \\
--client-ca-file=/opt/kubernetes/server/cert/ca.pem \\
--requestheader-client-ca-file=/opt/kubernetes/server/cert/ca.pem \\
--target-ram-mb=1024 \\
--audit-log-maxsize=100 \\
--audit-log-maxbackup=3 \\
--audit-log-maxage=30 \\
--audit-log-path=/opt/kubernetes/server/logs/k8s-audit.log \\
--log-dir=/opt/kubernetes/server/logs \\
--logtostderr=false \\
--v=2"
EOF
  1. systemd管理apiserver
1
2
3
4
5
6
7
8
9
10
11
12
13
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/opt/kubernetes/server/conf.d/kube-apiserver.conf
ExecStart=/opt/kubernetes/server/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
  1. 添加环境变量
    1
    2
    3
    4
    5
    6
    7
    cat >> /etc/profile << EOF
    # kubernetes-master
    export K8S_MASTER_HOME=/opt/kubernetes/server
    export PATH=\$PATH:\$K8S_MASTER_HOME/bin
    EOF

    source /etc/profile
  1. 启动并设置开机启动
    1
    2
    3
    4
    systemctl daemon-reload
    systemctl start kube-apiserver
    systemctl enable kube-apiserver
    systemctl status kube-apiserver
  1. 启用 TLS Bootstrapping 机制

TLS BootstrapingMaster apiserver启用TLS认证后,Node节点kubeletkube-proxy要与kube-apiserver进行通信,必须使用CA签发的有效证书才可以,当Node节点很多时,这种客户端证书颁发需要大量工作,同样也会增加集群扩展复杂度。为了简化流程,Kubernetes引入了TLS bootstraping机制来自动颁发客户端证书,kubelet会以一个低权限用户自动向apiserver申请证书,kubelet的证书由apiserver动态签署。所以强烈建议在Node上使用这种方式,目前主要用于kubeletkube-proxy还是由我们统一颁发一个证书。

  • TLS bootstraping 工作流程:

6.1.TLSbootstraping工作流程.png

# 1. 生成token

1
2
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
>> 331d24737f94d1c079bea05b312a59a1

# 2. 创建上述配置文件中token文件

1
2
3
4
5
cat > /opt/kubernetes/server/conf.d/token.csv << EOF
331d24737f94d1c079bea05b312a59a1,kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF

格式:token,用户名,UID,用户组

# 3. 授权kubelet-bootstrap用户允许请求证书

1
2
3
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap

6.2 kube-controller-manager部署

Controller Manager是Kubernetes最重要的核心组件之一,主要提供以下的功能:

  • 主要kube-controller-manager和cloud-controller-manager组成,是Kubernetes的大脑,它通过apiserver监控整个集群的状态,并确保集群处于预期的工作状态。
  1. 创建配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat > /opt/kubernetes/server/conf.d/kube-controller-manager.conf << EOF
KUBE_CONTROLLER_MANAGER_OPTS="--leader-elect=true \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=172.80.0.0/16 \\
--service-cluster-ip-range=192.168.80.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/server/cert/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/server/cert/ca-key.pem \\
--root-ca-file=/opt/kubernetes/server/cert/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/server/cert/ca-key.pem \\
--experimental-cluster-signing-duration=87600h0m0s \\
--log-dir=/opt/kubernetes/server/logs \\
--logtostderr=false \\
--v=2"
EOF

--master:通过本地非安全本地端口8080连接apiserver
--leader-elect:当该组件启动多个时,自动选举(HA)

  1. systemd管理controller-manager
1
2
3
4
5
6
7
8
9
10
11
12
13
cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/opt/kubernetes/server/conf.d/kube-controller-manager.conf
ExecStart=/opt/kubernetes/server/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
  1. 启动并设置开机启动
    1
    2
    3
    4
    systemctl daemon-reload
    systemctl start kube-controller-manager
    systemctl enable kube-controller-manager
    systemctl status kube-controller-manager

6.3 kube-scheduler部署

kube-schedulerKubernetes最重要的核心组件之一,主要提供以下的功能:

  • 负责分配调度Pod到集群内的节点上,它监听kube-apiserver,查询还未分配NodePod,然后根据调度策略为这些Pod分配节点(更新Pod的NodeName字段)。
  1. 创建配置文件
1
2
3
4
5
6
7
8
cat > /opt/kubernetes/server/conf.d/kube-scheduler.conf << EOF
KUBE_SCHEDULER_OPTS="--leader-elect=true \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1 \\
--log-dir=/opt/kubernetes/server/logs \\
--logtostderr=false \\
--v=2" \\
EOF
  1. systemd管理scheduler
1
2
3
4
5
6
7
8
9
10
11
12
13
cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/opt/kubernetes/server/conf.d/kube-scheduler.conf
ExecStart=/opt/kubernetes/server/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
  1. 启动并设置开机启动
    1
    2
    3
    4
    systemctl daemon-reload
    systemctl start kube-scheduler
    systemctl enable kube-scheduler
    systemctl status kube-scheduler
  1. 查看集群状态

所有组件都已经启动成功,通过kubectl工具查看当前集群组件状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master1 opt]# kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-2 Healthy {"health":"true"}
etcd-1 Healthy {"health":"true"}
etcd-0 Healthy {"health":"true"}
-----------------------------------
[root@k8s-master2 opt]# kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-1 Healthy {"health":"true"}
etcd-0 Healthy {"health":"true"}
etcd-2 Healthy {"health":"true"}
  1. 同理把master2也部署好apiserverschedulercontroller-manager

7. L4反向代理

  • Load Balancer(Master):192.168.1.51 - 192.168.1.50(VIP)
    • Nginx L4
  • Load Balancer(Backup):192.168.1.52
    • Nginx L4

7.1 拓扑图

7.1.l4负载图-new.png

7.2 nginx部署

  1. 安装nginx

    1
    yum install nginx -y
  2. nginx配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    vim /etc/nginx/nginx.conf  # 黏贴到http标签外
    stream {
    # kubernetes api-server ip地址以及https端口
    upstream kube-apiserver {
    server 192.168.1.30:6443 max_fails=3 fail_timeout=30s;
    server 192.168.1.31:6443 max_fails=3 fail_timeout=30s;
    }
    # 监听8443端口,将其接收的流量转发至指定proxy_pass
    server {
    listen 8443;
    proxy_connect_timeout 2s;
    proxy_timeout 900s;
    proxy_pass kube-apiserver;
    }
    }
  3. 启动nginx

    1
    systemctl start nginx && systemctl enable nginx && systemctl status nginx

7.3 keepalived部署

  1. 安装keepalived

    1
    yum install keepalived -y
  2. 监听脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    vim /etc/keepalived/check_port.sh
    #!/bin/bash
    # keepalived 监控端口脚本
    # 使用方法:
    # 在keepalived的配置文件中
    # vrrp_script check_port {# 创建一个vrrp_script脚本,检查配置
    # script "/etc/keepalived/check_port.sh 8443" # 配置监听的端口
    # interval 2 #检查脚本的频率,单位(秒)
    # }
    CHK_PORT=$1
    if [ -n "$CHK_PORT" ];then
    PORT_PROCESS=`ss -lnt|grep $CHK_PORT|wc -l`
    if [ $PORT_PROCESS -eq 0 ];then
    echo "Port $CHK_PORT Is Not Used,End."
    exit 1
    fi
    else
    echo "Check Port Cant Be Empty!"
    fi
  3. 添加可执行权限

    1
    chmod +x /etc/keepalived/check_port.sh
  4. keepalived主配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    # 主服务器
    cat > /etc/keepalived/keepalived.conf << EOF
    # Configuration File for keepalived
    global_defs {
    # 机器标识符,一般设置为hostname
    router_id load-balancer-master
    }
    vrrp_script chk_nginx {
    # 调用脚本检测nginx监听的8443端口是否存在
    script "/etc/keepalived/check_port.sh 8443"
    interval 2
    weight -20
    }
    vrrp_instance VI_1 {
    state MASTER
    interface ens192
    # 虚拟路由组id,两边须一致
    virtual_router_id 91
    priority 100
    advert_int 1
    # 当前主机IP
    mcast_src_ip 192.168.1.51
    # 不抢占
    nopreempt
    # 高可用认证
    authentication {
    auth_type PASS
    auth_pass jeremy # 认证密码,两边须一致
    }
    track_script {
    chk_nginx
    }
    # 虚拟IP
    virtual_ipaddress {
    192.168.1.50
    }
    }
    EOF


    # 备服务器
    cat > /etc/keepalived/keepalived.conf << EOF
    # Configuration File for keepalived
    global_defs {
    router_id load-balancer-backup
    }
    vrrp_script chk_nginx {
    script "/etc/keepalived/check_port.sh 8443"
    interval 2
    weight -20
    }
    vrrp_instance VI_1 {
    state BACKUP
    interface ens192
    virtual_router_id 91
    mcast_src_ip 192.168.1.52
    priority 90
    advert_int 1
    authentication {
    auth_type PASS
    auth_pass jeremy
    }
    track_script {
    chk_nginx
    }
    virtual_ipaddress {
    192.168.1.50
    }
    }
    EOF
  5. 启动keepalived

    1
    systemctl start keepalived && systemctl enable keepalived && systemctl status keepalived

8. Node节点部署

hostname 节点名称 IP
k8s-master1 node1 192.168.1.30
k8s-master2 node2 192.168.1.31
k8s-node3 node3 192.168.1.32
k8s-node4 node4 192.168.1.33
k8s-node5 node5 192.168.1.34
  • node节点主要部署两个服务
    • kubelet
    • kube-proxy
    • docker

8.1 kubelet部署

  1. 下载地址

下载地址

  1. 部署

kubernetes-node包里面的二进制文件跟kubernetes-server包里面给的是一样的

1
2
3
4
5
tar -xzvf kubernetes-node-linux-amd64.tar.gz

mkdir -p /opt/kubernetes/node/{bin,cert,conf.d,logs,kubeletData}

mv kubernetes/node/bin/* /opt/kubernetes/node/bin/
  1. 准备pause基础镜像

pause镜像是k8s里必不可少的以pod方式运行业务容器时的一个基础容器。

  • 在harbor上拉取镜像:docker pull kubernetes/pause

  • 上传镜像到harbor仓库

    1
    2
    docker tag f9d5de079539 harbor.jeremy.cn/public/pause:latest
    docker push harbor.jeremy.cn/public/pause:latest
  1. 登录harbor,创建目录,拷贝证书,环境变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 创建数据存储目录
    mkdir /opt/kubernetes/node/kubeletData

    # 登录harbor(账号:admin,密码:Harbor12345)
    docker login harbor.jeremy.cn

    # 拷贝证书
    scp ca.pem k8s-master1:/opt/kubernetes/node/cert

    # 环境变量
    cat >> /etc/profile << EOF
    # kubernetes-node
    export K8S_NODE_HOME=/opt/kubernetes/node
    export PATH=\$PATH:\$K8S_NODE_HOME/bin
    EOF

    source /etc/profile
  2. 创建配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    cat > /opt/kubernetes/node/conf.d/kubelet.conf << EOF
    KUBELET_OPTS="--hostname-override=k8s-master1 \\
    --kubeconfig=/opt/kubernetes/node/conf.d/kubelet.kubeconfig \\
    --bootstrap-kubeconfig=/opt/kubernetes/node/conf.d/kubelet-bootstrap.kubeconfig \\
    --config=/opt/kubernetes/node/conf.d/kubelet-config.yml \\
    --cert-dir=/opt/kubernetes/node/cert \\
    --root-dir=/opt/kubernetes/node/kubeletData \\
    --network-plugin=cni \\
    --pod-infra-container-image=harbor.jeremy.cn/public/pause:latest \\
    --log-dir=/opt/kubernetes/node/logs \\
    --logtostderr=false \\
    --v=2"
    EOF

    参数说明:
    --hostname-override:显示名称,集群中唯一(需要修改)
    --kubeconfig:空路径,会自动生成,后面用于连接apiserver
    --bootstrap-kubeconfig:首次启动向apiserver申请证书
    --config:配置参数文件
    --cert-dir:kubelet证书生成目录
    --pod-infra-container-image:管理Pod网络容器的镜像(这里用的是我们上传到harbor的pause镜像)
    --root-dir:设置用于管理kubelet文件的根目录(例如挂载卷的相关文件)(默认值为 “/var/lib/kubelet”)
    --network-plugin:启用cni,后面会部署fannel网络组件

  1. 配置参数文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    cat > /opt/kubernetes/node/conf.d/kubelet-config.yml << EOF
    kind: KubeletConfiguration
    apiVersion: kubelet.config.k8s.io/v1beta1
    address: 0.0.0.0
    port: 10250
    readOnlyPort: 10255
    cgroupDriver: cgroupfs
    clusterDNS:
    - 192.168.80.2
    clusterDomain: cluster.local
    failSwapOn: false
    authentication:
    anonymous:
    enabled: false
    webhook:
    cacheTTL: 2m0s
    enabled: true
    x509:
    clientCAFile: /opt/kubernetes/node/cert/ca.pem
    authorization:
    mode: Webhook
    webhook:
    cacheAuthorizedTTL: 5m0s
    cacheUnauthorizedTTL: 30s
    evictionHard:
    imagefs.available: 15%
    memory.available: 100Mi
    nodefs.available: 10%
    nodefs.inodesFree: 5%
    maxOpenFiles: 1000000
    maxPods: 110
    EOF
  2. 生成kubeconfig文件

  • 先写一个kubelet-boot.sh脚本 把下面的内容放进去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cat > /opt/kubernetes/node/kubelet-boot.sh << EOF
KUBE_APISERVER="https://192.168.1.50:8443" # apiserver VIP:PORT
BOOTSTRAP_TOKEN="331d24737f94d1c079bea05b312a59a1" # 与token.csv里保持一致

# 生成 kubelet-bootstrap.kubeconfig 文件

# 设置集群参数
kubectl config set-cluster kubernetes \\
--certificate-authority=/opt/kubernetes/node/cert/ca.pem \\
--embed-certs=true \\
--server=\${KUBE_APISERVER} \\
--kubeconfig=kubelet-bootstrap.kubeconfig

# 设置客户端认证参数
kubectl config set-credentials "kubelet-bootstrap" \\
--token=\${BOOTSTRAP_TOKEN} \\
--kubeconfig=kubelet-bootstrap.kubeconfig

# 设置上下文参数
kubectl config set-context default \\
--cluster=kubernetes \\
--user=kubelet-bootstrap \\
--kubeconfig=kubelet-bootstrap.kubeconfig

# 设置默认上下文
kubectl config use-context default --kubeconfig=kubelet-bootstrap.kubeconfig
EOF

--embed-certstrue时表示将certificate-authority证书写入到生成的bootstrap.kubeconfig文件中;
设置客户端认证参数时没有指定秘钥和证书,后续由kube-apiserver自动生成;

  • 生成kubelet-bootstrap.kubeconfig文件(生成的kubelet-bootstrap.kubeconfig文件放在配置文件目录中)
    1
    2
    3
    cd /opt/kubernetes/node/conf.d

    sh /opt/kubernetes/node/kubelet-boot.sh
  1. systemd管理kubelet

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    cat > /usr/lib/systemd/system/kubelet.service << EOF
    [Unit]
    Description=Kubernetes Kubelet
    After=docker.service

    [Service]
    EnvironmentFile=/opt/kubernetes/node/conf.d/kubelet.conf
    ExecStart=/opt/kubernetes/node/bin/kubelet \$KUBELET_OPTS
    Restart=on-failure
    LimitNOFILE=65535

    [Install]
    WantedBy=multi-user.target
    EOF
  2. 启动并设置开机启动

    1
    2
    3
    4
    systemctl daemon-reload
    systemctl start kubelet
    systemctl enable kubelet
    systemctl status kubelet
  3. 批准kubelet证书申请并加入集群

  • 查看kubelet证书请求
    kubectl get csr
    8.1.查看kubelet证书请求.png
  • 批准申请
    kubectl certificate approve name
    8.1.批准申请.png
  1. 建立一个 RBAC Role 来获取存取权限
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    cat >> apiserver-to-kubelet-rbac.yml << EOF
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
    labels:
    kubernetes.io/bootstrapping: rbac-defaults
    name: system:k8s-apiserver-to-kubelet
    rules:
    - apiGroups:
    - ""
    resources:
    - nodes/proxy
    - nodes/stats
    - nodes/log
    - nodes/spec
    - nodes/metrics
    verbs:
    - "*"
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: system:k8s-apiserver
    namespace: ""
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: system:k8s-apiserver-to-kubelet
    subjects:
    - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: k8s-apiserver
    EOF

    nameapiserver证书的CN字段;

  • 应用
    1
    kubectl create -f apiserver-to-kubelet-rbac.yml

8.2 kube-proxy部署

  1. 创建配置文件

    1
    2
    3
    4
    5
    6
    cat > /opt/kubernetes/node/conf.d/kube-proxy.conf << EOF
    KUBE_PROXY_OPTS="--config=/opt/kubernetes/node/conf.d/kube-proxy-config.yml \\
    --log-dir=/opt/kubernetes/node/logs \\
    --logtostderr=false \\
    --v=2"
    EOF
  2. 配置参数文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    cat > /opt/kubernetes/node/conf.d/kube-proxy-config.yml << EOF
    kind: KubeProxyConfiguration
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    metricsBindAddress: 0.0.0.0:10249
    clientConnection:
    kubeconfig: /opt/kubernetes/node/conf.d/kube-proxy.kubeconfig
    hostnameOverride: k8s-node1
    clusterCIDR: 192.168.80.0/24
    EOF

    PS: 需要修改hostnameOverride

  3. 创建证书

  • 查看 2.6 创建kube-proxy证书
  1. 拷贝证书

    1
    scp {kube-proxy.pem,kube-proxy-key.pem} k8s-master1:/opt/kubernetes/node/cert
  2. 生成kubeconfig文件

  • 先写一个kube-proxy-boot.sh脚本 把下面的内容放进去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat > /opt/kubernetes/node/kube-proxy-boot.sh << EOF
KUBE_APISERVER="https://192.168.1.50:8443" # apiserver VIP:PORT

# 生成 kube-proxy bootstrap kubeconfig 配置文件

# 设置集群参数
kubectl config set-cluster kubernetes \\
--certificate-authority=/opt/kubernetes/node/cert/ca.pem \\
--embed-certs=true \\
--server=\${KUBE_APISERVER} \\
--kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy \\
--client-certificate=/opt/kubernetes/node/cert/kube-proxy.pem \\
--client-key=/opt/kubernetes/node/cert/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
EOF
  • 生成
    1
    2
    cd /opt/kubernetes/node/conf.d
    sh /opt/kubernetes/node/kube-proxy-boot.sh
  1. systemd管理kube-proxy

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    cat > /usr/lib/systemd/system/kube-proxy.service << EOF
    [Unit]
    Description=Kubernetes Proxy
    After=network.target

    [Service]
    EnvironmentFile=/opt/kubernetes/node/conf.d/kube-proxy.conf
    ExecStart=/opt/kubernetes/node/bin/kube-proxy \$KUBE_PROXY_OPTS
    Restart=on-failure
    LimitNOFILE=65535

    [Install]
    WantedBy=multi-user.target
    EOF
  2. 启动并设置开机启动

    1
    2
    3
    4
    systemctl daemon-reload
    systemctl start kube-proxy
    systemctl enable kube-proxy
    systemctl status kube-proxy

到此就已经把各组件服务部署完毕,接下来就是把各节点的服务补充部署上去,查看集群状态,排错等等


9. fannel网络组件部署

  • 部署思路:
      1. 在node上下载cni依赖插件
      1. 在master上执行kube-flannel.yml

9.1 在kubelet中指定三个参数

这个本实例不需要,因为在部署kubelet的时候已经加了cni配置了

  • vim /opt/kubernetes/node/conf.d/kubelet.conf
    1
    2
    3
    --network-plugin=cni : 网络插件使用cni
    --cni-conf-dir=/etc/cni/net.d cni : 配置文件(默认)
    --cni-bin-dir=/opt/cni/bin cni : 可执行文件(默认)

9.1在kubelet中指定三个参数.png

  • 重启服务

    1
    systemctl restart kubelet && systemctl status kubelet
  • 这样在kublet启动的时候,就会去/etc/cni/net.d目录查找配置文件,并解析,使用相应的插件配置网络,因此之前node会从Ready变为NotReady

    1
    2
    3
    4
    [root@k8s-master1 logs]# kubectl get nodes
    NAME STATUS ROLES AGE VERSION
    k8s-node1 NotReady <none> 22h v1.18.10
    k8s-node2 NotReady <none> 22h v1.18.10

9.2 下载cni依赖插件

  1. 先准备好CNI二进制文件
    下载地址

  2. 解压二进制包并移动到默认工作目录

    1
    2
    mkdir /opt/cni/bin -p
    tar xzvf cni-plugins-linux-amd64-v0.8.7.tgz -C /opt/cni/bin

9.3 flannel网络组件部署

在master上进行此步操作

  1. 下载yml文件
    1
    2
    3
    cd /opt/cni/

    wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
  1. 修改yml文件 - 子网,工作模式

此处的network配置要与Pod Network(–service-cluster-ip-range)配置的一致

1
2
3
4
5
6
7
net-conf.json: |
{
"Network": "192.168.80.0/24",
"Backend": {
"Type": "vxlan"
}
}

Backend (工作模式)

  • Host-gw: 同一网段直接通信,速度快
  • udp: 用户空间的udp封装
  • vxlan: 利用内核vxlan协议进行传输(推荐)
  • aws vpc: 利用aws平台内部提供的功能进行传输
  1. 修改网卡

目前需要在kube-flannel.yml中使用- --iface参数指定集群主机内网网卡的名称,否则可能会出现dns无法解析。

1
2
3
4
5
6
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=ens192
  1. 准备镜像(目前不需要了)
  • 这一步目前好像不需要了,国内对v13版本的镜像好像可以直接拉去,如果不行,则只能按下面步骤进行操作

在国内下载flannel镜像同样很容易失败,因此建议提前下载好,再去启动flannel DaemonSet,避免在启动过程中重试浪费时间。(如果能科学上网,则可以下来下载,然后再进行手动导入)(本实例使用自己导入的镜像)
国内flannel镜像获取查看:https://www.cnblogs.com/xiao987334176/p/12696740.html#autoid-6-1-0
下载flannel镜像

  • 手动下载时镜像名称最好从kube-flannel.yml文件中拷贝,确保下载正确的镜像。

    1
    docker pull quay.io/coreos/flannel:v0.13.0
  • 导入镜像 并 修改好导入的镜像名称,跟配置文件名称保持一致

    1
    2
    docker load -i quay.io-coreos-flannel_v0.13.0.tar.gz
    docker tag e708f4bb69e3 quay.io/coreos/flannel:v0.13.0
    1
    2
    3
    initContainers:
    - name: install-cni
    image: quay.io/coreos/flannel:v0.13.0 # 配置文件中
  1. 在master上运行
    1
    2
    kubectl apply -f kube-flannel.yml
    kubectl get pods -n kube-system

9.1.在master上运行.png

1
kubectl get node

9.1.kubectl-get-node.png

10. Dashboard和CoreDNS部署

10.1 Dashboard部署

  1. 简介

    Kubernetes社区中,有一个很受欢迎的Dashboard项目,它可以给用户提供一个可视化的 Web 界面来查看当前集群的各种信息。用户可以用Kubernetes Dashboard部署容器化的应用、监控应用的状态、执行故障排查任务以及管理Kubernetes各种资源。

10.1.简介.png

  1. 相关地址
    官方参考文档

github项目地址

10.1.相关地址.png

  1. 下载yaml文件

    1
    wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml
  2. 修改yaml文件

  • vim recommended.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .....................
    kind: Service
    apiVersion: v1
    metadata:
    labels:
    k8s-app: kubernetes-dashboard
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard
    spec:
    ports:
    - port: 443
    targetPort: 8443
    nodePort: 38443
    type: NodePort
    selector:
    k8s-app: kubernetes-dashboard
    .....................

10.1.recommended.yaml.png

  1. 创建

    1
    kubectl apply -f recommended.yaml
  2. 查看状态

    1
    2
    3
    4
    5
    kubectl get pods,svc -n kubernetes-dashboard 

    kubectl get pods -n kubernetes-dashboard

    kubectl get svc -n kubernetes-dashboard

    10.1.查看状态.png

  1. 登录dashboard
  • 浏览器访问dashboard:
    1
    https://<any_node_ip>:38443

10.1.登录dashboard.png

  • Dashboard 支持 Kubeconfig 和 Token 两种认证方式,我们这里选择Token认证方式登录。

官方参考文档

  • 创建用户admin-user

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    cat > dashboard-adminuser.yaml << EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: admin-user
    namespace: kubernetes-dashboard
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: admin-user
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: cluster-admin
    subjects:
    - kind: ServiceAccount
    name: admin-user
    namespace: kubernetes-dashboard
    EOF
  • 创建

    1
    kubectl apply -f dashboard-adminuser.yaml

说明:上面创建了一个叫admin-user的服务账号,并放在kubernetes-dashboard命名空间下,并将cluster-admin角色绑定到admin-user账户,这样admin-user账户就有了管理员的权限。默认情况下,kubeadm创建集群时已经创建了cluster-admin角色,我们直接绑定即可。

  • 查看admin-user账户的token
    1
    kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

10.1.查看admin-user账户的token.png

  • 把token粘贴到登录窗口,然后登录
    10.1.把token粘贴到登录窗口,然后登录.png

10.1.登录.png

  • 删除管理员ServiceAccountClusterRoleBinding
    1
    2
    kubectl -n kubernetes-dashboard delete serviceaccount admin-user
    kubectl -n kubernetes-dashboard delete clusterrolebinding admin-user

10.2 CoreDNS部署

  1. 下载官方yaml文件样板

    1
    2
    3
    wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/coredns/coredns.yaml.base

    cp coredns.yaml.base coredns.yaml
  2. 修改yaml文件

  • 70行:__DNS__DOMAIN__ 改为cluster.local(这个值跟kubelet-config.yml文件内的clusterDomain值一致)
    10.2.修改yaml文件-1.png

  • 139行:__DNS__MEMORY__LIMIT__改为160Mi
    10.2.修改yaml文件-2.png

  • 205行:__DNS__SERVER__改为192.168.80.2(这个值跟kubelet-config.yml文件内的clusterDNS值一致)
    10.2.修改yaml文件-3.png

  • 注释112-114行

    1
    2
    3
    securityContext:
    seccompProfile:
    type: RuntimeDefault

    10.2.修改yaml文件-4.png

  • 修改镜像 135行 (下面是我上传到阿里镜像仓库的镜像)
    1
    registry.cn-hangzhou.aliyuncs.com/jeremy865/k8s-coredns:1.7.0
  1. 启动
    1
    kubectl apply -f coredns.yaml