采用二进制部署三主三工作节点的k8s集群,工作节点和Master节点共用服务器,因此只用到了三台服务器。master采用haproxy + keepalive实现高可用。实际生产环境中,建议主节点和工作节点分离。
另外本文用到的证书都是自签名的,如有CA认证中心,那么应该使用CA认证中心颁发的证书。
IP
主机名
系统版本
配置
备注
192.168.8.21
k8s-1
CentOS 7.6
4C4G
etcd、master、haproxy、keepalived、node
192.168.8.22
k8s-2
CentOS 7.6
4C4G
etcd、master、haproxy、keepalived、node
192.168.8.23
k8s-3
CentOS 7.6
4C4G
etcd、master、node
192.168.8.24
nil
nil
nil
haproxy + keepalived的虚拟IP
169.169.0.1
nil
nil
nil
Master Service虚拟服务的Cluster IP地址,集群内虚拟IP
169.169.0.100
nil
nil
nil
集群DNS服务的IP地址,集群内虚拟IP
为etcd和k8s启用CA认证的安全机制,需要CA证书进行配置。如果组织能够提供统一的CA认证中心,则直接使用组织颁发的CA证书即可。如果没有统一的CA认证中心,则可以通过颁发自签名的CA证书来完成安全配置。
etcd和k8s在制作CA证书时,均需要基于CA根证书。本文以k8s和etcd使用同一套的CA根证书为例。
# 生成私钥文件ca.key
openssl genrsa -out ca.key 2048
# 根据私钥文件生成根证书文件ca.crt
# /CN为master的主机名或IP地址
# days为证书的有效期
openssl req -x509 -new -nodes -key ca.key -subj "/CN=192.168.8.21" -days 36500 -out ca.crt
生成的两个ca文件放到 /etc/kubernetes/pki
目录下。
etcd.service内容
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target
[Service]
EnvironmentFile=/home/apps/etcd/etcd.conf
ExecStart=/usr/local/bin/etcd
Restart=always
[Install]
WantedBy=multi-user.target
etcd_ssl.cnf
[ req ]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[ alt_names ]
IP.1 = 192.168.8.21
IP.2 = 192.168.8.22
IP.3 = 192.168.8.23
创建etcd的服务端证书
openssl genrsa -out etcd_server.key 2048
openssl req -new -key etcd_server.key -config etcd_ssl.cnf -subj "/CN=etcd-server" -out etcd_server.csr
openssl x509 -req -in etcd_server.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_server.crt
创建etcd的客户端证书
openssl genrsa -out etcd_client.key 2048
openssl req -new -key etcd_client.key -config etcd_ssl.cnf -subj "/CN=etcd-client" -out etcd_client.csr
openssl x509 -req -in etcd_client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_client.crt
etcd.conf配置示例
ETCD_NAME=etcd1
ETCD_DATA_DIR=/home/apps/etcd/data
ETCD_CERT_FILE=/home/apps/etcd/pki/etcd_server.crt
ETCD_KEY_FILE=/home/apps/etcd/pki/etcd_server.key
ETCD_TRUSTED_CA_FILE=/etc/kubernetes/pki/ca.crt
ETCD_CLIENT_CERT_AUTH=true
ETCD_LISTEN_CLIENT_URLS=https://192.168.8.21:2379
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.8.21:2379
ETCD_PEER_CERT_FILE=/home/apps/etcd/pki/etcd_server.crt
ETCD_PEER_KEY_FILE=/home/apps/etcd/pki/etcd_server.key
ETCD_PEER_TRUSTED_CA_FILE=/etc/kubernetes/pki/ca.crt
ETCD_LISTEN_PEER_URLS=https://192.168.8.21:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.8.21:2380
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.8.21:2380,etcd2=https://192.168.8.22:2380,etcd3=https://192.168.8.23:2380"
ETCD_INITIAL_CLUSTER_STATE=new
验证
etcdctl --cacert=/etc/kubernetes/pki/ca.crt --cert=/home/apps/etcd/pki/etcd_client.crt --key=/home/apps/etcd/pki/etcd_client.key --endpoints=https://192.168.8.21:2379,https://192.168.8.22:2379,https://192.168.8.23:2379 endpoint health
下载二进制文件。https://github.com/kubernetes/kubernetes/releases。可以在changelog中找到二进制包的下载链接,比如:k8s 1.21。下载server binary和node binary即可
解压二进制压缩包,将可执行文件移到/usr/bin
tar xf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
find ./* -perm 755 -type f -exec mv {} /usr/bin \;
解压后主要文件说明
文件名
说明
apiextensions-apiserver
提供实现自定义资源对象的扩展API Server
kubeadm
Kubernetes集群安装的命令行工具
kube-aggregator
聚合API Server程序
kube-apiserver
kube-apiserver主程序
kube-apiserver.docker_tag
kube-apiserver的docker镜像tag
kube-apiserver.tar
kube-apiserver的docker镜像文件
kube-controller-manager
kube-controller-manager主程序
kube-controller-manager.docker_tag
kube-controller-manager的docker镜像tag
kube-controller-manager.tar
kube-controller-manager的docker镜像文件
kubectl
kubectl客户端命令行工具
kubelet
kubelet主程序
kube-proxy
kube-proxy主程序
kube-proxy.docker_tag
kube-proxy的docker镜像tag
kube-proxy.tar
kube-proxy的docker镜像文件
kube-scheduler
kube-scheduler主程序
kube-scheduler.docker_tag
kube-scheduler的docker镜像tag
kube-scheduler.tar
kube-scheduler的docker镜像文件
制作ca证书。编辑master_ssl.cnf文件
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
DNS.5 = k8s-1
DNS.6 = k8s-2
DNS.7 = k8s-3
IP.1 = 169.169.0.1
IP.2 = 192.168.8.21
IP.3 = 192.168.8.22
IP.4 = 192.168.8.23
IP.5 = 192.168.8.24
DNS.5 ~ DNS.7为三台服务器的主机名,另行设置/etc/hosts
IP.1为Master Service虚拟服务的Cluster IP地址,IP.2 ~ IP.4为apiserver的服务器IP,IP.5为负载均衡器的IP地址,可以为虚拟IP
制作证书文件。证书文件生成后将apiserver.crt
和apiserver.key
放到/etc/kubernetes/pki/
openssl genrsa -out apiserver.key 2048
openssl req -new -key apiserver.key -config master_ssl.cnf -subj "/CN=192.168.8.21" -out apiserver.csr
openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile master_ssl.cnf -out apiserver.crt
为kube-apiserver创建 systemd 服务配置文件。/usr/lib/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/etc/kubernetes/apiserver
ExecStart=/usr/bin/kube-apiserver $KUBE_API_ARGS
Restart=always
[Install]
WantedBy=multi-user.target
其中/etc/kubernetes/apiserver
的文件内容如下:
KUBE_API_ARGS="--insecure-port=0 \
--secure-port=6443 \
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt \
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key \
--client-ca-file=/etc/kubernetes/pki/ca.crt \
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
--service-account-key-file=/etc/kubernetes/pki/sa.pub \
--service-account-signing-key-file=/etc/kubernetes/pki/sa-key.pem \
--apiserver-count=3 --endpoint-reconciler-type=master-count \
--etcd-servers=https://192.168.8.21:2379,https://192.168.8.22:2379,https://192.168.8.23:2379 \
--etcd-cafile=/etc/kubernetes/pki/ca.crt \
--etcd-certfile=/home/apps/etcd/pki/etcd_client.crt \
--etcd-keyfile=/home/apps/etcd/pki/etcd_client.key \
--service-cluster-ip-range=169.169.0.0/16 \
--service-node-port-range=30000-32767 \
--allow-privileged=true \
--logtostderr=false --log-dir=/var/log/kubernetes --v=0"
主要参数说明:
参数
说明
insecure-port
HTTP端口号,默认值为8080,0表示关闭http访问
secure-port
HTTPS端口号,默认值为6443
tls-cert-file
服务端CA证书的绝对路径
tls-private-key-file
服务端CA证书私钥的绝对路径
apiserver-count
apiserver的实例数
endpoint-reconciler-type
apiserver-count参数的依赖项
allow-privileged
是否允许容器以特权模式运行
logtostderr
是否将日志输出到标准错误,默认为true
log-dir
日志目录。需要事先创建
--v
日志级别
使用cfssl创建sa.pub和sa-key.pem
cat<
{
"CN":"sa",
"key":{
"algo":"rsa",
"size":2048
},
"names":[
{
"C":"CN",
"L":"BeiJing",
"ST":"BeiJing",
"O":"k8s",
"OU":"System"
}
]
}
EOF
cfssl gencert -initca sa-csr.json | cfssljson -bare sa -
openssl x509 -in sa.pem -pubkey -noout > sa.pub
在三台服务器启动apiserver
systemctl daemon-reload
systemctl start kube-apiserver && systemctl enable kube-apiserver
systemctl status kube-apiserver
创建客户端CA证书。将生成的client.crt和client.key放到/etc/kubernetes/pki
openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=admin" -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 36500
为kube-controller-manager、kube-scheduler、kubelet和kube-proxy统一创建一个kubeconfig文件作为连接apiserver的配置文件,后续kubectl连接apiserver的配置文件。
apiVersion: v1
kind: Config
clusters:
- name: default
cluster:
server: https://192.168.8.24:9443
certificate-authority: /etc/kubernetes/pki/ca.crt
users:
- name: admin
user:
client-certificate: /etc/kubernetes/pki/client.crt
client-key: /etc/kubernetes/pki/client.key
contexts:
- context:
cluster: default
user: admin
name: default
current-context: default
将 kubeconfig 文件保存到 /etc/kubernetes 目录下。
创建systemd配置文件。/usr/lib/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/etc/kubernetes/controller-manager
ExecStart=/usr/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_ARGS
Restart=always
[Install]
WantedBy=multi-user.target
编辑 /etc/kubernetes/controller-manager
KUBE_CONTROLLER_MANAGER_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig <br /> --leader-elect=true <br /> --service-cluster-ip-range=169.169.0.0/16 <br /> --service-account-private-key-file=/etc/kubernetes/pki/apiserver.key <br /> --root-ca-file=/etc/kubernetes/pki/ca.crt <br /> --log-dir=/var/log/kubernetes --logtostderr=false --v=0"
启动
systemctl daemon-reload
systemctl start kube-controller-manager && systemctl enable kube-controller-manager
systemctl status kube-controller-manager
创建systemd配置文件。/usr/lib/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/etc/kubernetes/scheduler
ExecStart=/usr/bin/kube-scheduler $KUBE_SCHEDULER_ARGS
Restart=always
[Install]
WantedBy=multi-user.target
编辑 /etc/kubernetes/scheduler
KUBE_SCHEDULER_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig <br /> --leader-elect=true <br /> --logtostderr=false --log-dir=/var/log/kubernetes --v=0"
启动
systemctl daemon-reload
systemctl start kube-scheduler && systemctl enable kube-scheduler
systemctl status kube-scheduler
编辑 haproxy.cfg
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/lib/haproxy.pid
maxconn 4096
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend kube-apiserver
mode tcp
bind *:9443
option tcplog
default_backend kube-apiserver
listen stats
mode http
bind *:8888
stats auth admin:password
stats refresh 5s
stats realm HAProxy\ Statistics
stats uri /stats
log 127.0.0.1 local3 err
backend kube-apiserver
mode tcp
balance roundrobin
server k8s-master1 192.168.8.21:6443 check
server k8s-master2 192.168.8.22:6443 check
server k8s-master3 192.168.8.23:6443 check
haproxy.cfg 主要配置说明:
编辑docker-compose.yaml
version: "3"
services:
haproxy:
image: "haproxytech/haproxy-debian:2.3"
container_name: k8s-haproxy
network_mode: host
restart: always
volumes:
- /home/apps/haproxy/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
在192.168.8.21和192.168.8.22启动haproxy。启动后访问 8888 端口,然后输入账号密码即可访问状态监控的web页面
docker-compose up -d
编辑192.168.8.11的 keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_1
}
vrrp_script checkhaproxy
{
script "/usr/bin/check-haproxy.sh"
interval 2
weight -30
}
vrrp_instance VI_1 {
state MASTER
interface ens192
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
192.168.8.24/16 dev ens192
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
checkhaproxy
}
}
主要配置说明:
编辑 check-haproxy.sh。记得赋予可执行权限
#!/bin/bash
count=netstat -apn | grep 9443 | wc -l
if [ $count -gt 0 ]; then
exit 0
else
exit 1
fi
编辑192.168.8.22的 keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_2
}
vrrp_script checkhaproxy
{
script "/usr/bin/check-haproxy.sh"
interval 2
weight -30
}
vrrp_instance VI_1 {
state BACKUP
interface ens192
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
192.168.8.24/16 dev ens192
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
checkhaproxy
}
}
在8.21和8.22分别启动keepalived的docker容器
docker run -d --name k8s-keepalived --restart=always --net=host --cap-add=NET_ADMIN --cap-add=NET_BROADCAST --cap-add=NET_RAW -v ${PWD}/keepalived.conf:/container/service/keepalived/assets/keepalived.conf -v ${PWD}/check-haproxy.sh:/usr/bin/check-haproxy.sh osixia/keepalived:2.0.20 --copy-service
测试。执行:curl -v -k https://192.168.8.24:9443,如有类似以下输出,则说明通过vip成功访问到后端服务
GET / HTTP/1.1
User-Agent: curl/7.29.0
Host: 192.168.8.24:9443
Accept: /< HTTP/1.1 401 Unauthorized
< Cache-Control: no-cache, private
< Content-Type: application/json
< Date: Sat, 07 Jan 2023 17:30:30 GMT
< Content-Length: 165
<
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
在node上需要部署docker、kubelet、kube-proxy,加入k8s集群后,还需要部署CNI网络插件、DNS插件等。
编辑 /usr/lib/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://github.com/kubernetes/kubernetes
After=docker.target
[Service]
EnvironmentFile=/etc/kubernetes/kubelet
ExecStart=/usr/bin/kubelet $KUBELET_ARGS
Restart=always
[Install]
WantedBy=multi-user.target
编辑 /etc/kubernetes/kubelet。注意修改hostname-override
中的IP为Node节点自己的IP
KUBELET_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig <br /> --config=/etc/kubernetes/kubelet.config <br /> --hostname-override=192.168.8.21 <br /> --network-plugin=cni <br /> --logtostderr=false --log-dir=/var/log/kubernetes --v=0"
主要参数说明:
参数
说明
--kubeconfig
设置与 apiserver 连接的配置,可以与 controller-manager 的 kubeconfig 相同。新的Node节点注意拷贝客户端相关证书文件,比如ca.crt, client.key, client.crt
--config
kubelet 配置文件,设置可以让多个Node共享的配置参数。
--hostname-override
本Node在集群中的名称,默认值为主机名
--network-plugin
网络插件类型,推荐使用CNI网络插件
编辑 /etc/kubernetes/kubelet.config
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
cgroupDriver: systemd
clusterDNS: ["169.169.0.100"]
clusterDomain: cluster.local
authentication:
anonymous:
enabled: true
主要参数说明:
参数
说明
address
服务监听IP地址
port
服务监听端口号,默认值为10250
cgroupDriver
cgroupDriver驱动,默认值为cgroupfs,可选 systemd
clusterDNS
集群DNS服务的IP地址
clusterDomain
服务DNS域名后缀
authentication
是否允许匿名访问或者是否使用webhook鉴权
在Node主机启动kubelet服务并设置为开机自启动
systemctl daemon-reload
systemctl start kubelet && systemctl enable kubelet
systemctl status kubelet
编辑 /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
EnvironmentFile=/etc/kubernetes/proxy
ExecStart=/usr/bin/kube-proxy $KUBE_PROXY_ARGS
Restart=always
[Install]
WantedBy=multi-user.target
编辑 /etc/kubernetes/proxy。注意修改hostname-override
为Node主机自己的IP
KUBE_PROXY_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig <br /> --hostname-override=192.168.8.21 <br /> --proxy-mode=iptables <br /> --logtostderr=false --log-dir=/var/log/kubernetes --v=0"
启动
systemctl daemon-reload
systemctl start kube-proxy && systemctl enable kube-proxy
systemctl status kube-proxy
在master节点通过kubectl查询自动注册到 k8s 的 node 信息。由于 Master 开启了 https 认证,所以 kubectl 也需要使用客户端 CA证书连接Master,可以直接使用 kube-controller-manager 的 kubeconfig 文件
kubectl --kubeconfig=/etc/kubernetes/kubeconfig get nodes
NAME STATUS ROLES AGE VERSION
192.168.8.21 NotReady
192.168.8.22 NotReady
192.168.8.23 NotReady
部署calico
kubectl --kubeconfig=/etc/kubernetes/kubeconfig apply -f calico.yaml
kubectl --kubeconfig=/etc/kubernetes/kubeconfig get nodes
NAME STATUS ROLES AGE VERSION
192.168.8.21 Ready
192.168.8.22 Ready
192.168.8.23 Ready
kubectl --kubeconfig=/etc/kubernetes/kubeconfig get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-846d7f49d8-4n572 1/1 Running 0 36m
calico-node-j857l 1/1 Running 0 36m
calico-node-k8txx 1/1 Running 0 36m
calico-node-n2cdd 1/1 Running 0 36m
nil
k8s处理提供基于CA证书的认证方式,也提供基于HTTP Token的简单认证方式。各客户端组件与API Server之间的通信方式仍然采用HTTPS,但不采用CA数字证书。这种认证方式与CA证书相比,安全性很低,不建议在生产环境中使用。
基于Token认证的配置过程如下:
创建包括用户名、密码和UID的文件 token_auth_file,将其放置在合适的目录下。该文件为纯文本文件,用户名、密码都是明文。
cat /etc/kubernetes/token_auth_file
admin,admin,1
system,system,2
配置 apiserver 启动参数
--token-auth-file=/etc/kubernetes/token_auth_file
原因:1.20后需要添加service-account-issuer
参数
解决:生成sa证书和pub
cat<
{
"CN":"sa",
"key":{
"algo":"rsa",
"size":2048
},
"names":[
{
"C":"CN",
"L":"BeiJing",
"ST":"BeiJing",
"O":"k8s",
"OU":"System"
}
]
}
EOF
cfssl gencert -initca sa-csr.json | cfssljson -bare sa -
openssl x509 -in sa.pem -pubkey -noout > sa.pub
查看pod信息
kubectl --kubeconfig=/etc/kubernetes/kubeconfig get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-846d7f49d8-4n572 0/1 Pending 0 12m
calico-node-j857l 0/1 Init:0/3 0 12m
calico-node-k8txx 0/1 Init:0/3 0 12m
calico-node-n2cdd 0/1 Init:0/3 0 12m
kubectl --kubeconfig=/etc/kubernetes/kubeconfig describe pod calico-node-j857l -n kube-system
docker pull 'registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.4.1'
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.4.1 'k8s.gcr.io/pause:3.4.1'
《Kubenetes权威指南 - 第五版》
CSDN - kubernetes 1.21.10 apiserver报错 Error: service-account-issuer is a required flag
手机扫一扫
移动阅读更方便
你可能感兴趣的文章