从K8S部署示例进一步理解容器化编排技术的强大

概念

Kubernetes,也称为K8s,生产级别的容器编排系统,是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。K8s是一个go语言开发,docker也是go语言开发,可见go语言的是未来的趋势;从公有云Iaas、Paas、Saas的云计算时代开始,到Docker Swarm用于容器化集群和Apache Mesos为分布式资源管理框架,Kubernetes最终打败其他容器化编排技术成为主流引领者。

kubeadm部署

部署规划

服务器最低配置要求: 2core 、2G、 50G,由于需要部署docker,因此如果是centos则要求7以上

所有服务器的操作系统

cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
主机名 IP
k8s-master2 192.168.50.36
k8s-node-1 192.168.50.34
k8s-node-2 192.168.50.35

网段划分

名称 IP网段 备注
service-cluster-ip 10.10.0.0/16 可用地址 65534
pods-ip 10.20.0.0/16 可用地址 65534
集群dns 10.10.0.2 用于集群service域名解析
k8s svc 10.10.0.1 集群 kubernetes svc 解析ip

部署步骤

下面是所有的节点均需操作

#部署docker,找出最新版本 
yum list docker-ce --showduplicates | sort -r
yum list docker-ce-cli --showduplicates | sort -r
#修改为最新的版本
yum -y install docker-ce-20.10.8 docker-ce-cli-20.10.8 containerd.io

#添加/etc/docker/daemon.json内容为
{
"registry-mirrors": ["//b9pmyelo.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重启docker
systemctl restart docker
systemctl enable docker.service
#关闭防火墙
systemctl stop firewalld # 临时
systemctl disable firewalld # 永久

#关闭 selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
setenforce 0 # 临时

#关闭 swap
swapoff -a # 临时
vim /etc/fstab # 永久

#修改主机名
hostnamectl set-hostname <hostname>

#添加 hosts
cat >> /etc/hosts << EOF
192.168.50.34 k8s-node-1
192.168.50.35 k8s-node-2
192.168.50.36 k8s-master-2
EOF

#使桥接流量对iptables可见,将桥接的 IPv4 流量传递到 iptables 的链
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

#时间同步
yum install ntpdate -y
ntpdate time.windows.com

# 使用本地软件包管理软件安装 kubectl 二进制文件
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=//mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=//mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg //mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

#安装 kubeadm,kubelet 和 kubectl
yum install -y kubelet-1.22.1 kubeadm-1.22.1 kubectl-1.22.1
systemctl enable kubelet

image-20210916144804267

查看已安装版本信息

image-20210916145124707

kubeadm init --kubernetes-version=1.22.1 \
--apiserver-advertise-address=192.168.50.36 \
--ignore-preflight-errors=all \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.10.0.0/16 \
--pod-network-cidr=10.20.0.0/16

image-20210916160448137

根据上面的提示信息继续操作

kubectl get nodesmkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
#下面这段是后面在node节点加入k8s集群的命令
kubeadm join 192.168.50.36:6443 --token jagf90.w67s5swmocymags3 \
	--discovery-token-ca-cert-hash sha256:0afe56b1ca4354bc1148bf25c97e18412ab4f1340d3b62080d1fb1d0901d07c9 
# 如需要重新生成token重新生成加入集群命令可使用下面这个
kubeadm token create --print-join-command
#查看当前集群节点信息,目前集群的网络还没有打通,因此状态为NotReady
kubectl get nodes
#查看当前节点的docker镜像,kubeadm部署方式是以docker镜像方式运行集群
docker images

image-20210916163524566

分别在两台node节点192.168.50.34、192.168.50.35执行加k8s集群的命令

kubeadm join 192.168.50.36:6443 --token jagf90.w67s5swmocymags3 \
	--discovery-token-ca-cert-hash sha256:0afe56b1ca4354bc1148bf25c97e18412ab4f1340d3b62080d1fb1d0901d07c9 

image-20210916165016766

#使kubectl自动补全
source <(kubectl completion bash)
# 查询目前三个节点的信息如下
kubectl get nodes
kubectl get pod --all-namespaces -o wide

image-20210916165111924

接下来需要给k8s集群添加CNI网络插件,有很多方式,这里先提供两种

#calico网络
kubectl apply -f //docs.projectcalico.org/manifests/calico.yaml          
#或者选择kube-flannel网络
kubectl apply -f //raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
#过两分钟后再查看节点的状态

image-20210916170305883

image-20210917230153343

image-20210917230304013

通过查找pod的详细信息发现问题

#calico.yaml先下载下来
wget //docs.projectcalico.org/manifests/calico.yaml
#calico.yaml增加两行信息 - name: IP_AUTODETECTION_METHOD value: "interface=ens.*",interface后面根据实际,我的机器网卡是ens160所以直接填
            # Cluster type to identify the deployment type
            - name: CLUSTER_TYPE
              value: "k8s,bgp"
            - name: IP_AUTODETECTION_METHOD
              value: "interface=ens160"
            # Auto-detect the BGP IP address.
            - name: IP
              value: "autodetect"
#重新应用calico.yaml             
kubectl apply -f calico.yaml  

image-20210917230709263

我们再来解决coredns的ImagePullBackOff的问题

image-20210917230906547

#查看coredns pod的镜像
kubectl get pods coredns-7f6cbbb7b8-d2rzk -n kube-system -o yaml | grep image    
#显示信息如下
    image: registry.aliyuncs.com/google_containers/coredns:v1.8.4
    imagePullPolicy: IfNotPresent
  - image: registry.aliyuncs.com/google_containers/coredns:v1.8.4
    imageID: ""
        message: Back-off pulling image "registry.aliyuncs.com/google_containers/coredns:v1.8.4"
#由于registry.aliyuncs.com/google_containers/coredns:v1.8.4官方是没有的,官方镜像是coredns/coredns:1.8.4
#在coredns节点上也即是k8s-node-2也即是192.168.50.35上先下载镜像
docker pull coredns/coredns:1.8.4
#查看coredns/coredns:1.8.4镜像的imageid,给镜像手动打tag为registry.aliyuncs.com/google_containers/coredns:v1.8.4
docker tag 8d147537fb7d registry.aliyuncs.com/google_containers/coredns:v1.8.4

image-20210917231316719

image-20210917231440318

常见几个问题

1.  加入集群时报错: /etc/kubernetes/kubelet.conf already exists

原因: 上次的配置文件没有清理干净,删除即可

rm -rf /etc/kubernetes/kubelet.conf /etc/kubernetes/pki/ca.crt
2.   加入集群时报错: [ERROR Port-10250]: Port 10250 is in use

原因:上次加入没有成功就关闭。重置kubeadm

kubeadm reset
 3. 加入集群报错:/proc/sys/net/ipv4/ip_forward contents are not set to 1

echo "1" >/proc/sys/net/ipv4/ip_forward

容器编排示例

nginx部署示例

所有命令不清楚就是用–help这个万能的神命令查看,这里采用deployment部署,当然也可以单独创建pod,这种在实际场景会比较少用

#创建nginx部署
kubectl create deployment nginx --image=nginx
#暴露端口 type类型可以有多种
kubectl expose deployment nginx --port=80 --type=NodePort
#查看pods和services的信息,这里是缩写,其他缩写可以查询--help命令,像上面deployment缩写为deploy,对应复数可是可以使用,一般使用简写
kubectl get pod,svc -o wide

image-20210916173451992

上面有几个Ip和端口需要理解下。k8s-node-1的ip是192.168.50.34,宿主机上的端口为32173,所以我们可以通过//192.168.50.34:32173 访问到这个pod暴露的服务

image-20210916173643231

#更新镜像版本
kubectl set image deploy nginx nginx=nginx:1.7.9
#查看更新状态
kubectl rollout status deploy nginx
#describe显示特定资源或资源组的详细信息,这里显示nginx部署详细信息
kubectl describe deploy nginx

image-20210917141923017

#回退到上一次的版本
kubectl rollout undo deploy nginx
#查看deployment变更的对应版本
kubectl rollout history deploy nginx
#查看deployment变更的对应版本的细节
kubectl rollout history deploy nginx --revision=7
#回滚到指定的版本
kubectl rollout undo deploy nginx --to-revision=7

# kubectl proxy主要用于测试,可以通过
kubectl proxy
curl //localhost:8001/api/v1/proxy/namespaces/default/pods/podname访问

image-20210917151457981

容器扩缩容示例

#扩容nginx pod数量为4
kubectl scale deploy nginx --replicas=4
#查看pod信息,第一次查询结果k8s-node-1上pod马上就有,应该k8s-node-1之前下载了nginx镜像,第二次k8s-node-2下载完镜像也启动两个pod,k8s有自己的算法比较均衡将pod分布集群节点上
kubectl get pod -o wide
#缩容nginx pod数量为2,
kubectl scale deploy kubernetes-bootcamp --replicas=2

image-20210917143610845

基于yaml文件方式部署

上面我们都是基于kubectl也即是命令方式直接创建deployment和pod、service,这种方式一般是简单测试使用,接下来我们基于yaml文件方式部署

编写单独创建pod的yaml文件nginx-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.7.9
      ports:
      - containerPort: 80
# 通过create命令用yaml来创建pod,另外还可以使用apply命令用yaml来创建
kubectl create -f nginx-pod.yaml

image-20210917145919844

编写创建deploy的yaml文件nginx-deploy.yaml,也可以直接通过下面命令生成一个deployment的yaml文件

kubectl create deployment nginx-d1 --image=nginx:1.18 -o yaml --dry-run > nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx-deploment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.18
        name: nginx
        resources: {}
status: {}
#删除deployment
kubectl delete deploy nginx
# 基于yaml创建deployment
kubectl apply -f nginx-deploy.yaml
#查看labels标签为app=nginx的pod,上面选择器为app=nginx,我们创建多个pod,找到label,services也是根据这个label找到然后做负载均衡
kubectl get pods -l app=nginx
#可以查看pod的日志,和我们之前docker logs一样
kubectl logs pod -f

image-20210917153236540

接下来我们看下service部分,也即是kubernetes的ingress来暴露应用,创建nginx-service.yaml文件

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 8080
    targetPort: 80
    nodePort: 30080
  selector:
    app: nginx
  type: NodePort

#创建service
kubectl create -f nginx-service.yaml
#查看创建service详细信息,安装完系统有一个名称为kubernetes的service,这个相当把apiserver做成一个ip
kubectl describe service nginx-service

image-20210917154618381

有几个重要端口我们一起来了解下

  • nodePort:这个是提供给集群外部的集群访问的,像这类配置为30080则可以提供给外部访问,比如这里直接访问//192.168.50.34:30080,service内部实现服务发现和负载均衡

image-20210917155331649

  • targetPort:容器的端口,与制作容器镜像时暴露端口一致,和我们之前学习docker制作dockerfile文件是一样的,例如我们这里的测试的nginx,docker.io官方镜像暴露端口就是80
  • port:这个是kubernetes集群内部各个服务之间互相访问的端口,比如我们mysql容器虽然暴露3306端口,没有配置nodePort,外部无法直接访问容器,但集群内部容器之间是可以通过访问mysql服务

我们可以进入任意一个容器进行测试,我们进入到kubernetes-bootcamp,然后访问nginx的pod服务

#由于目前这个容器只有一个pod
kubectl exec -it kubernetes-bootcamp /bin/bash
#如果有多个pod,那就需要通过docker命令找到容器的名称指定了
kubectl exec -it kubernetes-bootcamp --container xxxxx /bin/bash
#进入一个装有工具箱的环境,一般用于测试
kubectl run busybox --rm=true --image=busybox --restart=Never --tty -i

image-20210917160859014

生成10.20网段的地址是容器内的地址,10.10网段是用于集群内容通信的地址,也可以pod直接访问 ,比如我们这里的//10.10.11.146

image-20210917175759484

image-20210917175741729

基于dns访问集群

#查询所有命名空间的service,kube-dns集群地址为10.10.0.10,这个是kubeadm创建dns服务
kubectl  get svc -A
#如果是手动安装我们可以通过apply方式部署dns,kube-dns.yaml,下载地址可以网上找,比如//github.com/liuyi01/kubernetes-starter/blob/master/kubernetes-with-ca/services/kube-dns.yaml
kubectl apply -f kube-dns.yaml

image-20210918092423301

可以通过nginx-service名称访问到nginx的服务

image-20210918093901511

安装仪表盘

# 下载 dashboard.yaml 文件到本地,可以在github kubernetes dashboard项目上查看最新版本,目前U最新版本为v2.3.1
wget //raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
kubectl apply -f recommended.yaml
kubectl proxy

image-20210916175926722

# 设置可以在外部访问dashboard,修改 dashboard以 nodePort 访问,编辑配置文件
kubectl -n kubernetes-dashboard edit service kubernetes-dashboard
修改类型
type: ClusterIP 
改为
type: NodePort
#查看暴露的端口
kubectl -n kubernetes-dashboard get service kubernetes-dashboard

image-20210916180136840

通过节点访问//192.168.50.34:30109/#/login 页面

image-20210916180556615

在我们上面下载recommended.yaml文件里面就有subjects,表示创建了 kubernetes-dashbord 账户

image-20210917162233195

# 为该账户创建登录 token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard | awk '{print $1}')

Data
====
ca.crt:     1099 bytes
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Im5EOGxxZHFIdnFKeTRabmlicHhRNDVBZ3Y0WlR1enRLQkdoZ21EcFExLWcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi1xenNiayIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjcyNGQ0ODRmLTY2M2YtNGM2YS1hNGMyLTVlOTk3OTliYzczMyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.czIcgip4VJe7dEY_nulArhqKtd2Lc3JGlUrNmn4jGc2ZZ5TMeluRvv71Sztdmb-iYftWKnqil-OuCBgTFss6atShfiQ3__2i4V-vBAM1cFjBtxKZ0QgOpRvDri0hAj34XnF9uSzjH24Gt4x50OX9qaIKmJ8ppHVe0lxBWXP-Z-N4JbrKkRbD6c-EwYBhMoJo7ndUGmkxVsCvuNaE4yRfXENRaunPmGYJMgvFo4XSAz37cznNNVVj8BaIbSxgxv8XPgUEdQZxP2bm2TskVb3AYqeSVd4YR87NxYFod91IezRUBelbupaVWllJVcsEIaANfk4NNN61atWkGO9aNgyK4Q

将上面的token复制,点击登录即可

image-20210917163000126