一般常用的k8s集群的部署方式有两种:
本次部署k8s-1.17.2,之所以不安装最新版本,是因为之后还要进行k8s集群升级的实验。
一个最基础的高可用k8s集群环境需要以下几个部分:
本次准备的实验环境:
角色/hostname | 物理网络 IP 地址 | 配置 | 系统 |
---|---|---|---|
master1 | 192.168.1.101 | 2c-2g-50G | Ubuntu 1804 |
master2 | 192.168.1.102 | 2c-2g-50G | Ubuntu 1804 |
master3 | 192.168.1.103 | 2c-2g-50G | Ubuntu 1804 |
lb1 | 192.168.1.104 | 1c-1g-20G | Ubuntu 1804 |
lb2 | 192.168.1.105 | 1c-1g-20G | Ubuntu 1804 |
harbor | 192.168.1.106 | 1c-2g-100G | Ubuntu 1804 |
node1 | 192.168.1.107 | 4c-4g-100G | Ubuntu 1804 |
node2 | 192.168.1.108 | 4c-4g-100G | Ubuntu 1804 |
所有服务器均安装必要的工具、设置好主机名、配置内核参数和资源限制参数,需要特别注意的是:
具体的服务器初始准备可以参考博客《centos系统初始化》以及《ubuntu系统初始化》。
物理网络不用赘述,在k8s集群中要规划好两个网络:
本次的规划:
网络类型 | 网段 |
---|---|
物理网络 | 192.168.1.0/24 |
Service网络 | 172.16.0.0/20 |
Pod网络 | 10.10.0.0/16 |
角色/hostname | 物理网络 IP 地址 | 配置 | 系统 |
---|---|---|---|
lb1 | 192.168.1.104 | 1c-1g-20G | Ubuntu 1804 |
lb2 | 192.168.1.105 | 1c-1g-20G | Ubuntu 1804 |
通过Haproxy+Keepalived的方式实现高可用负载均衡。
将lb1设置为MASTER,lb2设置为BACKUP,添加vip 192.168.1.248,用于k8s集群管理端的访问入口。
lb1:
vrrp_instance VIP {
state MASTER
interface eth0
garp_master_delay 10
smtp_alert
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.248 dev eth0 label eth0:1
}
}
lb2:
vrrp_instance VIP {
state BACKUP
interface eth0
garp_master_delay 10
smtp_alert
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.248 dev eth0 label eth0:1
}
}
两台Haproxy的配置保持一致。
配置监听vip的6443端口,来代理k8s集群的apiServer接口;将3台k8s-master设置为后端服务器。
listen k8s-api-6443
bind 192.168.1.248:6443
mode tcp
server k8s-master1 192.168.1.101:6443 check inter 3s fall 3 rise 5
server k8s-master2 192.168.1.102:6443 check inter 3s fall 3 rise 5
server k8s-master3 192.168.1.103:6443 check inter 3s fall 3 rise 5
角色/hostname | 物理网络 IP 地址 | 配置 | 系统 |
---|---|---|---|
harbor | 192.168.1.106 | 1c-2g-100G | Ubuntu 1804 |
本次安装1.7.5版本的harbor
直接通过脚本,基于apt的方式安装docker-ce。
脚本内容:
#!/bin/bash
# apt install docker-ce & docker-compose.
sudo apt-get update;
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common;
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -;
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable";
sudo apt-get -y update;
sudo apt-get -y install docker-ce docker-ce-cli docker-compose
解压并创建软链,易于后期版本管理。
root@harbor:/usr/local/src# tar xf harbor-offline-installer-v1.7.5.tgz
root@harbor:/usr/local/src# mv harbor harbor-v1.7.5
root@harbor:~# ln -sv /usr/local/src/harbor-v1.7.5/ /usr/local/harbor
配置:
root@harbor:~# vim /usr/local/harbor/harbor.cfg
hostname = harbor.yqc.com #harbor访问地址
harbor_admin_password = 123456 #admin用户密码
注意,因为本次实验环境没有私有DNS服务,所以后期要在每个需要使用harbor的服务器上配置静态的hosts解析:
192.168.1.106 harbor.yqc.com
初始化配置:
root@harbor:~# cd /usr/local/harbor
root@harbor:/usr/local/harbor# ./prepare
在/lib/systemd/system
中添加harbor的服务脚本harbor.service
。
根据实际情况更改docker-compose的二进制路径和harbor的部署路径。
[Unit]
Description=Harbor
After=docker.service systemd-networkd.service systemd-resolved.service
Requires=docker.service
Documentation=http://github.com/vmware/harbor
[Service]
Type=simple
Restart=on-failure
RestartSec=5
ExecStart=/usr/bin/docker-compose -f /usr/local/harbor/docker-compose.yml up
ExecStop=/usr/bin/docker-compose -f /usr/local/harbor/docker-compose.yml down
[Install]
WantedBy=multi-user.target
重载daemon
systemctl daemon reload
开启harbor并设为开机自启:
systemctl start harbor
systemctl enable harbor
访问http://harbor.yqc.com/,admin/123456
角色/hostname | 物理网络 IP 地址 | 配置 | 系统 |
---|---|---|---|
master1 | 192.168.1.101 | 2c-2g-50G | Ubuntu 1804 |
master2 | 192.168.1.102 | 2c-2g-50G | Ubuntu 1804 |
master3 | 192.168.1.103 | 2c-2g-50G | Ubuntu 1804 |
node1 | 192.168.1.107 | 4c-4g-100G | Ubuntu 1804 |
node2 | 192.168.1.108 | 4c-4g-100G | Ubuntu 1804 |
K8s节点需要安装Docker、集群创建工具kubeadm、节点代理程序kubelet。kubectl在集群创建时不是必需的。
需要注意的是程序版本:
为k8s集群所有的master和node节点准备Docker运行环境(包括容器镜像拉取的配置和优化)。
关于 Docker 版本的选择,在github的kubernets项目的版本changelog中找到相应k8s版本支持的Docker版本,进行安装。
比如1.17版本的changelog:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#v1173,中有支持到docker 19.03版本的提示。
所以安装19.03版本的docker,修改docker的apt安装脚本,指定一下docker-ce的版本,然后执行脚本进行安装。
#!/bin/bash
# install docker on k8s nodes
sudo apt-get update;
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common;
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -;
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable";
sudo apt-get -y update;
sudo apt-get -y install docker-ce=5:19.03.15~3-0~ubuntu-bionic docker-ce-cli=5:19.03.15~3-0~ubuntu-bionic;
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"] #阿里云的镜像加速服务,具体地址请到自己的阿里云帐号进行获取。
}
EOF
k8s推荐使用的Cgroup为systemd,而Docker默认为cgroupfs,所以修改一下。
编辑 /etc/docker/daemon.json
(没有该文件就新建一个),添加如下启动项参数即可:
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
要想Docker成功在私有harbor上拉取/上传镜像,需要将harbor添加为insecure-registry。
在docker的systemd脚本/lib/systemd/system/docker.service
中的启动命令ExecStart
后添加--insecure-registry
选项,指定自己的harbor地址。
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry harbor.yqc.com
同时在/etc/hosts
中添加主机解析(有自己的DNS服务就添加A记录):
192.168.1.106 harbor.yqc.com
所有配置工作结束后重启Docker。
systemctl restart docker && systemctl enable docker
根据需要在节点上安装相应程序:
其余组件在kubeadm搭建的k8s集群中都是容器化运行的,比如kube-proxy、etcd等。
版本:https://github.com/kubernetes/kubernetes/releases/tag/v1.17.2
为所有节点添加kubernets源,这里选用阿里云。
apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat << EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
安装前先查看一下kubernetes源中包含的版本,确认一下版本号的指定方式。
apt-cache madison kubeadm
安装指定版本的kubeadm和kubelet。
apt install kubeadm=1.17.2-00 kubelet=1.17.2-00 -y
注意kubelet安装后是启动不了的,需要k8s集群初始化完成、或者节点添加到k8s集群后,相应节点上的kubelet才会启动。
关于kubeadm init的官方文档:https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/
集群初始化的过程,就是从指定镜像仓库中拉取对应版本的k8s组件镜像,并根据指定的集群参数,将各组件容器运行起来。
注意:
kubeadm init
即可,且只执行一次。kubeadm join
加入集群。执行kubeadm config images list --kubernetes-version v1.17.2
,查看1.7.2版本的k8s需要哪些镜像:
k8s.gcr.io/kube-apiserver:v1.17.2
k8s.gcr.io/kube-controller-manager:v1.17.2
k8s.gcr.io/kube-scheduler:v1.17.2
k8s.gcr.io/kube-proxy:v1.17.2
k8s.gcr.io/pause:3.1
k8s.gcr.io/etcd:3.4.3-0
k8s.gcr.io/coredns:1.6.5
可以看到默认是从k8s.gcr.io
拉取镜像的,为了提升速度,将谷歌的镜像仓库替换为阿里云,然后执行docker pull
把镜像拉取下来 :
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.17.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.17.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.17.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.17.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.3-0
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.6.5
查看拉取的镜像:
root@k8s-master1:~# docker image list
初始化有两种方式:
kubeadm init
命令行传参;kubeadm init --config CONFIG_FILE
指定配置文件。kubeadm init \
--apiserver-advertise-address=192.168.1.101 \ #apiserver的监听地址(本机)
--apiserver-bind-port=6443 \ #apiserver的监听端口
--control-plane-endpoint=192.168.1.248 \ #k8s集群管理地址(设为固定的vip地址)
--ignore-preflight-errors=swap \ #忽略swap的检查报错
--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers \ #镜像仓库地址
--kubernetes-version=v1.17.2 \ #要安装的k8s版本
--pod-network-cidr=10.10.0.0/16 \ #pod网络的地址段(与网络组件的地址段要一致)
--service-cidr=172.16.0.0/20 \ #service网络的地址段
--service-dns-domain=yqc.com #service的域名(创建的service名称后缀)
先获取到初始化的默认参数,保存到文件中
kubeadm config print init-defaults > kubeadm-init-1.17.2.yml
修改默认参数:
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.1.101 #修改为本机的地址
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: k8s-master1.yqc.com
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: 192.168.1.248:6443 #添加此参数,指定k8s集群的管理地址和端口
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers #修改镜像仓库为阿里云
kind: ClusterConfiguration
kubernetesVersion: v1.17.2 #修改为要安装的k8s版本
networking:
dnsDomain: yqc.com #修改为自己的域名
podSubnet: 10.10.0.0/16 #添加此参数,指定Pod网络的地址范围
serviceSubnet: 172.16.0.0/20 #修改为自己规划的service网络地址范围
scheduler: {}
然后指定配置文件,执行初始化:
kubeadm init --config kubeadm-init-1.17.2.yml
初始化成功后,会返回一些信息,需要记录下来,用于后边为kubectl进行管理授权、部署集群网络组件,以及添加其它节点到集群。
以下为返回信息:
Your Kubernetes control-plane has initialized successfully!
#如何为当前系统用户进行kubectl管理授权:
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#如何部署网络组件:
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
#如何添加其它master节点:
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join 192.168.1.248:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:2186235afb370fbc0eda9a241f2fc877f66cce4e76f4cae121e6bf686769d55d \
--control-plane
#如何添加node节点:
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.248:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:2186235afb370fbc0eda9a241f2fc877f66cce4e76f4cae121e6bf686769d55d
安装 kubectl:
apt install -y kubectl=1.17.2-00
为当前用户进行kubectl的管理授权(通常为root用户添加kubectl的管理权限):
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
/etc/kubernetes/admin.conf
中保存的是集群管理地址,以及集群管理认证所需的密钥,将其放置在当前用户的$HOME/.kube/config
后,当用户执行kubectl命令时,就会调用其中的配置,从而可以通过对应的k8s集群的管理认证,进而可以对k8s集群进行管理操作。
尝试执行kubectl命令:
可以执行表示设置成功,当前系统用户已经可以通过kubectl管理k8s集群了。
root@k8s-master2:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master2.yqc.com NotReady master 11m v1.17.2
NotReady的状态是由于集群的网络组件还未部署,kubelet还无法正常获取节点状态。
这里使用flannel作为k8s集群的Pod网络组件。
github的flannel项目中关于在k8s中部署flannel的说明:https://github.com/flannel-io/flannel#deploying-flannel-manually
Deploying flannel manually
Flannel can be added to any existing Kubernetes cluster though it’s simplest to add flannel before any pods using the pod network have been started.For Kubernetes v1.17+ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
先把kube-flannel.yml下载下来,修改其中的配置,将网段更改为自己规划的pod网段。
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp.flannel.unprivileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
privileged: false
volumes:
- configMap
- secret
- emptyDir
- hostPath
allowedHostPaths:
- pathPrefix: "/etc/cni/net.d"
- pathPrefix: "/etc/kube-flannel"
- pathPrefix: "/run/flannel"
readOnlyRootFilesystem: false
# Users and groups
runAsUser:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
fsGroup:
rule: RunAsAny
# Privilege Escalation
allowPrivilegeEscalation: false
defaultAllowPrivilegeEscalation: false
# Capabilities
allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
defaultAddCapabilities: []
requiredDropCapabilities: []
# Host namespaces
hostPID: false
hostIPC: false
hostNetwork: true
hostPorts:
- min: 0
max: 65535
# SELinux
seLinux:
# SELinux is unused in CaaSP
rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
rules:
- apiGroups: ['extensions']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['psp.flannel.unprivileged']
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-system
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.10.0.0/16", #修改为自己的Pod网段
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-system
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.14.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
kubectl apply -f kube-flannel.yml
flannel的控制器是DaemonSet,所以后期新添加的节点上,都会运行一个flannel的Pod。
为初始化后的k8s集群添加节点时,需要使用--certificate-key
指定密钥,需要提前创建一下。
执行:
kubeadm init phase upload-certs --upload-certs
结果:
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
4c2a009a1367866d5b2525a82a02545f3c4cc8f4db370804eaab3f997d608d42
确保节点已经安装了docker、 kubeadm 和 kubelet 。
在需要添加为master的节点上运行:
kubeadm join 192.168.1.248:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:2186235afb370fbc0eda9a241f2fc877f66cce4e76f4cae121e6bf686769d55d \
--certificate-key 4c2a009a1367866d5b2525a82a02545f3c4cc8f4db370804eaab3f997d608d42 \
--control-plane
添加master节点的过程中也需要拉取所需的组件镜像,所以也可以提前拉取。
如果添加成功,会返回如下信息:
两台master节点上执行添加操作后,在master1上查看当前集群中的节点:
root@k8s-master1:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master1.yqc.com Ready master 32m v1.17.2
k8s-master2.yqc.com Ready master 28m v1.17.2
k8s-master3.yqc.com Ready master 24m v1.17.2
同样,确保节点已经安装了docker、 kubeadm 和 kubelet 。
在需要添加为woker node的节点上执行:
kubeadm join 192.168.1.248:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:2186235afb370fbc0eda9a241f2fc877f66cce4e76f4cae121e6bf686769d55d \
--certificate-key 4c2a009a1367866d5b2525a82a02545f3c4cc8f4db370804eaab3f997d608d42
添加成功后的返回信息:
添加完两台node节点后,此时,查看k8s集群的节点:
root@k8s-master1:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1.yqc.com Ready master 39m v1.17.2
k8s-master2.yqc.com Ready master 35m v1.17.2
k8s-master3.yqc.com Ready master 31m v1.17.2
k8s-node1.yqc.com Ready 3m40s v1.17.2
k8s-node2.yqc.com Ready 3m22s v1.17.2
github搜索kubernetes/dashboard项目,在releases中找到和1.17版本的k8s完全兼容的dashboard版本。
最好在自己的harbor中上传一份当前所用的dashboard镜像,便于后期重建Pod。
把部署dashboard所需的两个镜像拉取下来,并上传到harbor(提前创建好相应的项目):
root@k8s-master1:~# docker pull kubernetesui/dashboard:v2.0.0-rc6
root@k8s-master1:~# docker pull kubernetesui/metrics-scraper:v1.0.3
root@k8s-master1:~# docker images | egrep '(scraper|dashboard)'
kubernetesui/dashboard v2.0.0-rc6 cdc71b5a8a0e 14 months ago 221MB
kubernetesui/metrics-scraper v1.0.3 3327f0dbcb4a 15 months ago 40.1MB
root@k8s-master1:~# docker tag cdc71b5a8a0e harbor.yqc.com/base-images/dashboard:v2.0.0-rc6
root@k8s-master1:~# docker tag 3327f0dbcb4a harbor.yqc.com/base-images/metrics-scraper:v1.0.3
root@k8s-master1:~# docker push harbor.yqc.com/base-images/dashboard:v2.0.0-rc6
root@k8s-master1:~# docker push harbor.yqc.com/base-images/metrics-scraper:v1.0.3
在github的kubernetes/dashboard项目中下载dashboard的yml文件。
默认的yml文件不能直接用,因为其中使用的是默认的Service类型(Clusterip),不能通过外部访问到Dashboard。
而我们部署Dashboard是想要通过外部访问来管理k8s集群的,所以要将Service的类型定义为NodePort,并为其指定监听端口(这里定义监听在30002),同时,将镜像更改为自己harbor中的镜像,提升拉取速度。
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Namespace
metadata:
name: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort #指定type为NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30002 #定义nodePort监听端口
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
data:
csrf: ""
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-key-holder
namespace: kubernetes-dashboard
type: Opaque
---
kind: ConfigMap
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-settings
namespace: kubernetes-dashboard
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
rules:
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster", "dashboard-metrics-scraper"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
verbs: ["get"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kubernetes-dashboard
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: harbor.yqc.com/base-images/dashboard:v2.0.0-rc6 #私有harbor中的镜像
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
"beta.kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
ports:
- port: 8000
targetPort: 8000
selector:
k8s-app: dashboard-metrics-scraper
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: dashboard-metrics-scraper
template:
metadata:
labels:
k8s-app: dashboard-metrics-scraper
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
spec:
containers:
- name: dashboard-metrics-scraper
image: harbor.yqc.com/base-images/metrics-scraper:v1.0.3 #私有harbor中的镜像
ports:
- containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTP
path: /
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 30
volumeMounts:
- mountPath: /tmp
name: tmp-volume
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
"beta.kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
volumes:
- name: tmp-volume
emptyDir: {}
作用是为dashboard进行管理授权,使其具有管理k8s集群的权限。
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
root@k8s-master1:~/dashboard-v2.0.0-rc6# kubectl apply -f dashboard-v2.0.0-rc6.yml -f admin-user.yml
验证pod是否运行:
root@k8s-master1:~# kubectl get pod -n kubernetes-dashboard
kubernetes-dashboard dashboard-metrics-scraper-6f86cf95f5-hlppq 1/1 Running 0 51s
kubernetes-dashboard kubernetes-dashboard-857797b456-7mtv5 1/1 Running 0 52s
访问任一node节点的30002端口,都可以打开dashboard,因为nodePort会在所有node节点上监听:
node1:
root@k8s-node1:~# ss -tnlp | grep 30002
LISTEN 0 20480 *:30002 *:* users:(("kube-proxy",pid=89002,fd=8))
node2:
root@k8s-node2:~# ss -tnlp | grep 30002
LISTEN 0 20480 *:30002 *:* users:(("kube-proxy",pid=89653,fd=8))
要通过https访问dashboard,访问https://192.168.1.107:30002/或https://192.168.1.108:30002/
需要认证,有两种方式:
kubeconfig
配置文件(原型为/etc/kubernetes/admin.conf
),导入文件进行登录。找到admin-user的secret名称:
root@k8s-master1:~# kubectl get secret -A | grep admin-user
kubernetes-dashboard admin-user-token-5rcp6 kubernetes.io/service-account-token 3 9m40s
查看这个secret的详细信息,其中有对应的token:
root@k8s-master1:~# kubectl describe secret admin-user-token-5rcp6 -n kubernetes-dashboard
Name: admin-user-token-5rcp6
Namespace: kubernetes-dashboard
Labels:
Annotations: kubernetes.io/service-account.name: admin-user
kubernetes.io/service-account.uid: e59a6b13-e197-4538-b531-99e7bf738f7e
Type: kubernetes.io/service-account-token
Data
====
namespace: 20 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImJmM1FSamgyYTBSVGxEdW96NzcxbzFqZDVaUkdRejZaaElKQ1h4eWFQTjQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLTVyY3A2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJlNTlhNmIxMy1lMTk3LTQ1MzgtYjUzMS05OWU3YmY3MzhmN2UiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.PjXK_RYVBctcGBg99vSzaAFo-xSD6Jw53R0WJKi75KpH-tibNS5attjj0Dny3FaCcH7MFL8yphidQFiff9xQ2T1Tb9vAus3zTJSw4yiKW9wqyXUvJmXZ7MfjSXmppar4M_zhxatkKxz8Hs6bJiKj2YHOGuxbwSisBP5lBRVzPSrP1Nms0QBSCOPU0JUyVDPJg8GNo6cEP1NX6cLJbFdaErD9hVpM9r8yaHxbemprgTlnBkwSexLKvA6W8E1FS9c7WMhNj_uALfzbuJT2HcUuQDqeEdzDHwM3M_lew_MX836EmFMb5FThHEIZkRZcNUp70VQGabGLzZXvrMmYa5VsJg
ca.crt: 1025 bytes
将token粘到访问页面:
点登录就可以了
使用token登录Dashboard的有效期默认是15min,每次退出重新找token再登录比较费事,有三种解决办法:
创建kubeconfig文件(将/etc/kubernetes/admin.conf
文件复制出来,在kubernetes-admin这个user下添加token字段,并将token值复制到其中)
root@k8s-master1:~# cp /root/.kube/config /opt/kubeconfig
root@k8s-master1:~# vim /opt/kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxxxxxxxxx
server: https://192.168.1.248:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: xxxxxxx
client-key-data: xxxxxxxxxxx
token: #将token粘到这里
然后将kubeconfig文件放到PC端
root@k8s-master1:~# sz /opt/kubeconfig
以后在登录时选择kubeconfig,并选择对应的kubeconfig文件,就可以登录了
最后,在haproxy中添加一个30002端口的vip监听,将各node节点的30002端口添加为后端服务器。
listen k8s-dashboard-30002
bind 192.168.1.248:30002
mode tcp
server 192.168.1.107 192.168.1.107:30002 check inter 3s fall 3 rise 5
server 192.168.1.108 192.168.1.108:30002 check inter 3s fall 3 rise 5
这样,只要为vip添加一个dashboard的域名解析,就可以通过域名访问到dashboard了。
192.168.1.248 dashboard.yqc.com
创建几个测试Pod,验证k8s集群的运行和网络环境。
以alpine为镜像,创建测试Pod,3个副本:
kubectl run net-test1 --image=alpine --replicas=3 sleep 360000
kubectl get pod
进行查看,运行正常:
NAME READY STATUS RESTARTS AGE
net-test1-5fcc69db59-l96z8 1/1 Running 0 37s
net-test1-5fcc69db59-t666q 1/1 Running 0 37s
net-test1-5fcc69db59-xkg7n 1/1 Running 0 37s
通过kubectl get pod -o wide
可以看到有两个pod被分配到node1,1个被分配到node2:
进入一个容器,ping同宿主机的pod、跨宿主机的pod、外网,如果均正常,则网络环境正常:
root@k8s-master1:~# kubectl exec -it net-test1-5fcc69db59-cjchg sh
/ # ping 10.10.4.2
PING 10.10.4.2 (10.10.4.2): 56 data bytes
64 bytes from 10.10.4.2: seq=0 ttl=64 time=0.205 ms
64 bytes from 10.10.4.2: seq=1 ttl=64 time=0.077 ms
^C
--- 10.10.4.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.077/0.141/0.205 ms
/ # ping 10.10.3.2
PING 10.10.3.2 (10.10.3.2): 56 data bytes
64 bytes from 10.10.3.2: seq=0 ttl=62 time=12.454 ms
64 bytes from 10.10.3.2: seq=1 ttl=62 time=0.779 ms
^C
--- 10.10.3.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.779/6.616/12.454 ms
/ # ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: seq=0 ttl=127 time=0.199 ms
^C
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.199/0.199/0.199 ms
/ # ping 223.6.6.6
PING 223.6.6.6 (223.6.6.6): 56 data bytes
64 bytes from 223.6.6.6: seq=0 ttl=127 time=17.979 ms
64 bytes from 223.6.6.6: seq=1 ttl=127 time=15.503 ms
^C
/ # ping www.baidu.com
PING www.baidu.com (110.242.68.4): 56 data bytes
64 bytes from 110.242.68.4: seq=0 ttl=127 time=16.309 ms
64 bytes from 110.242.68.4: seq=1 ttl=127 time=23.715 ms
kubeadm reset
,还原系统环境,确认无误后再次执行初始化或添加节点的操作。