Ubuntu下Kubernetes(k8s)集群搭建

黎汝聪 2024-08-02 14:37:01 阅读 68

文章目录

1.基本概念1.1Master节点1.2worker节点1.3Pod1.4Controller1.5Service

2.环境搭建2.1安装指定版本docker2.2关闭swap分区2.3安装kubeadm、kubectl和kubelet2.4配置Master节点2.5配置worker节点

3.基本操作3.1Kubectl使用3.2集群资源清单3.3NameSpace3.4Pod3.5Controller控制器3.5.1部署无状态应用(Deployment)3.5.2部署有状态应用(StatefulSet)

3.6Service3.7Secret3.7.1secret.yaml(数据要自己base64加密)3.7.2以Volume的形式挂载到Pod中

3.8ConfigMap3.8.1以变量形式挂载到pod3.8.2以volume形式挂载到Pod中

附录:yaml具体解释

1.基本概念

1.1Master节点

apiserver:集群统一入口,以restful方式,交给etcd存储

scheduler:节点调度,选择worker节点应用部署

controller-manager:处理集群中常规后台任务,一个资源对应一个控制器

etcd:存储系统,用于保存集群相关的数据

1.2worker节点

kubelet:master派到node节点的代表,管理本机容器

kube-proxy:提供网络代理,负载均衡等操作

1.3Pod

最小部署单元一组容器的集合共享网络生命周期是短暂的

1.4Controller

确保预期的Pod副本数量无状态应用部署有状态应用部署一次性任务和定时任务

1.5Service

定义一组Pod的访问规则

2.环境搭建

安装版本,采用kubeadm搭建,k8s的组件均运行在docker容器中

ubuntu kubernetes docker
22.04 LTS 1.23.5-00 5:20.10.14~3-0~ubuntu-jammy

2.1安装指定版本docker

参考docker官网安装教程

<code>#准备工具

sudo apt-get update

sudo apt-get install ca-certificates curl gnupg

#Add Docker’s official GPG key

sudo install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

sudo chmod a+r /etc/apt/keyrings/docker.gpg

#set up the repository

echo \

"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \code>

"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \

sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

#查看版本号

sudo apt-cache madison docker-ce

#安装指定版本

sudo apt-get install docker-ce=5:20.10.14~3-0~ubuntu-jammy docker-ce-cli=5:20.10.14~3-0~ubuntu-jammy containerd.io

#docker compose,docker官网安装教程中有,可不安装,不影响运行

#sudo apt-get install containerd.io docker-buildx-plugin docker-compose-plugin

#换仓库地址,写入配置文件

sudo vim /etc/docker/daemon.json

#写入加速器地址

{

"registry-mirrors": ["https://hub-mirror.c.163.com/"]

}

sudo systemctl daemon-reload

sudo systemctl restart docker

#配置docker,kubernetes默认设置cgroup驱动(cgroupdriver)为"systemd",而docker服务的cgroup驱动默认为"cgroupfs",建议将其修改为"systemd",与kubernetes保持一致

#再次修改daemon.json,在其后添加一行"exec-opts":["native.cgroupdriver=systemd"]

sudo vim /etc/docker/daemon.json

{

"registry-mirrors": ["https://hub-mirror.c.163.com/"],

"exec-opts":["native.cgroupdriver=systemd"]

}

sudo systemctl daemon-reload

sudo systemctl restart docker

2.2关闭swap分区

sudo vim /etc/fstab

#注释掉 /swapfile 所在行,然后重启计算机即可永久关闭swap

2.3安装kubeadm、kubectl和kubelet

kubelet: k8s sh的核心服务kubeadm: 这个是用于快速安装 k8s 的一个集成工具,我们在master1和worker1上的 k8s 部署都将使用它来完成。kubectl: k8s 的命令行工具,部署完成之后后续的操作都要用它来执行

#更新apt源

sudo apt-get update

#使apt支持ssl传输

sudo apt-get install -y apt-transport-https

#下载gpg密钥

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -

#添加apt源

sudo apt-add-repository "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main"

#查看可安装版本

sudo apt-cache madison kubectl

#安装指定版本

sudo apt-get install kubelet=1.23.5-00 kubeadm=1.23.5-00 kubectl=1.23.5-00

#阻止自动更新

sudo apt-mark hold kubelet kubeadm kubectl

2.4配置Master节点

#查看集群使用的容器镜像

kubeadm config images list

#拉取所需镜像

sudo kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

#初始化

#配置项说明:

#--apiserver-advertise-address k8s 中服务apiserver的部署地址,如果不填写,默认是本机

#--image-repository 拉取的 docker 镜像源,因为初始化的时候kubeadm会去拉 k8s 的很多组件来进行部署,所以需要指定国内镜像源,下不然会拉取不到镜像

#--pod-network-cidr k8s采用的节点网络,该参数指定了为pod节点分配的虚拟ip网段

#--kubernetes-version: 这个是用来指定你要部署的 k8s 版本的,一般不用填,不过如果初始化过程中出现了因为版本不对导致的安装错误的话,可以用这个参数手动指定

kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.5 --pod-network-cidr=192.168.0.0/16 --apiserver-advertise-address=192.168.121.130

#初始化

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

#查看集群节点

kubectl get nodes

#查看集群状态

kubectl get cs

#以上步骤安装完后,机器搭建起来了,但状态还是NotReady状态,master机器需要安装网络插件Calico

#下面是一个网上别人整理好的资源清单,之间运行k8s会在docker中拉起相应的服务

kubectl apply -f https://docs.projectcalico.org/v3.21/manifests/calico.yaml

#再次查看集群节点,状态变为Ready

kubectl get nodes

#查看集群状态

kubectl get cs

输出信息如下,执行其中的mkdir,cp等命令,最后的输出kubeadm join命令用于worker节点加入集群

Your Kubernetes control-plane has initialized successfully!

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

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.121.130:6443 --token 1uwxx8.zkr71sdz5uu7z2t1 \

--discovery-token-ca-cert-hash sha256:5d0df7efc1d8895ec4c93e7d926738d4311fd36b6f14b18dffbaf4e07d66213d

2.5配置worker节点

#更新apt源

sudo apt-get update

#使apt支持ssl传输

sudo apt-get install -y apt-transport-https

#下载gpg密钥

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -

#添加apt源

sudo apt-add-repository "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main"

#查看可安装版本

sudo apt-cache madison kubectl

#安装指定版本

sudo apt-get install kubelet=1.23.5-00 kubeadm=1.23.5-00 kubectl=1.23.5-00

#阻止自动更新

sudo apt-mark hold kubelet kubeadm kubectl

#加入集群

sudo kubeadm join 192.168.121.130:6443 --token 1uwxx8.zkr71sdz5uu7z2t1 \

--discovery-token-ca-cert-hash sha256:5d0df7efc1d8895ec4c93e7d926738d4311fd36b6f14b18dffbaf4e07d66213d

#查看token和hash

kubeadm token list

kubeadm token inspect <token名称>

#新建token

kubeadm token create --print-join-command

#部署完后在master节点查看

kubectl get nodes

#输出如下:

#NAME STATUS ROLES AGE VERSION

#lzy-virtual-machine Ready control-plane,master 35m v1.23.5

#worker-node1 Ready <none> 2m7s v1.23.5

3.基本操作

3.1Kubectl使用

环境准备,将主节点的.kube/config文件复制到worker节点中

#使用命令验证

kubectl get nodes

#查看命令

kubectl --help

#查看生成的标签

kubectl get node --show-labels

#给节点node2打上标签env=prod

kubectl label node node2 env=prod

3.2集群资源清单

用于资源编排

yaml文件组成部分,由控制器定义和被控制对象组成,示例:

#控制器定义

apiVersion: apps/v1

kind: Deployment #资源类型

metadata:

name: nginx-deployment

namespace: default

spec:

replicas: 1 #副本数量

selector:

matchLabels:

app: nginx

#被控制对象

template: #Pod模板

metadata: #Pod元数据

labels:

app: nginx

spec:

containers: #容器配置

- name: nginx #容器名称

image: nginx:1.18 #容器镜像

imagePullPolicy: IfNotPresent #获取镜像的策略

ports: #Pod的重启策略

- containerPort: 80 #容器需要监听的端口号

restartPolicy: Always #Pod的重启策略

常用字段说明

参数名 数据类型 说明
apiVersion String 指k8s API的版本,可以用kubectl api-versions命令查看,一般为v1
kind String 指yaml文件定义的资源类型和角色,比如Pod
metadata Object 元数据对象
metadata.name String 元数据对象的名字,这里由我们编写
metadata.namespace String 元数据对象的命名空间
spec Object 详细定义对象
spec.containers[] list 容器列表
spec.containers[].name String 容器名
spec.containers[].name String 镜像名称
spec.containers[].imagePullPolicy String 容器镜像拉取策略,Always、Never、Ifnotpresent

<code>#应用资源清单文件

kubectl apply -f fileName.yaml

#使用kubectl create命令生成yaml文件

kubectl create deployment test --image=nginx:1.18 -o yaml --dry-run > my1.yaml

#使用kubectl get命令导出yaml文件

#旧版本为kubectl get deploy nginx-app -o=yaml --export > my2.yaml

kubectl get deploy nginx-app -o=yaml > my2.yaml

3.3NameSpace

实现资源隔离属于逻辑隔离属于管理边界不属于网络边界可以针对每个namespace做资源隔离

#查看命名空间

kubectl get namespace

#以下为输出

#NAME STATUS AGE

#default Active 2d17h

#kube-node-lease Active 2d17h

#kube-public Active 2d17h

#kube-system Active 2d17h

#其中default为用户创建pod的默认命名空间

#kube-public 为所有用户均可访问的命名空间,包括未认证用户

#kube-node-lease 为kubernetes集群节点租约状态,v1.13加入

#kube-system kubernetes集群使用的命名空间

#创建命名空间

kubectl create namespace test

#删除命名空间

kubectl delete namespace test

3.4Pod

一个Pod中的多个容器可以共享存储和网络,可以看作一个逻辑的主机。共享的如namespace,cgroups 或者其他的隔离资源。

pod实现共享网络机制:Pod中首先自动创建Pause容器(根容器),再创建业务容器,并将业务容器加入根容器,让所有业务容器在同一个namespace中,实现网络共享

pod实现共享存储机制:引入数据卷概念Volumn,实现共享存储

查看pod

#查看pod

kubectl get pods

#或

kubectl get pods --namespace default

#进入pod

kubectl exec -it [podName] bash

创建pod,以部署nginx应用为例

#拉取镜像

sudo docker pull nginx:1.18

资源清单nginx.yaml

apiVersion: v1

kind: Pod

metadata:

name: pod1

namespace: default

spec:

containers:

- name: nginx-pod

image: nginx:1.18

imagePullPolicy: IfNotPresent

ports:

- name: nginxport

containerPort: 80

创建pod,创建pod时scheduler会使用调度算法将pod分配给相应的node

#应用资源清单文件

kubectl apply -f nginx.yaml

#查看是否成功创建

kubectl get pods -o wide

#输出为

#NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

#pod1 1/1 Running 0 3m34s 192.168.180.193 worker-node1 <none> <none>

#可通过192.168.180.193进行访问

#删除pod

kubectl delete pods pod1 -n default

3.5Controller控制器

在集群上管理和运行容器的对象

当pod出现问题时,会把pod重新拉起,以达到用户的期望状态

常见Pod控制器

控制器名称 作用
Deployment 声明式更新控制器,用于发布无状态应用
ReplicaSet 副本集控制器,用于对Pod进行副本规模扩大或裁剪
StatefulSet 有状态副本集,用于发布有状态应用
DaemonSet 在k8s集群每一个Node上运行一个副本,用于发布监控或日志收集类等应用
Job 运行一次性作业任务
CronJob 运行周期性作业任务

<code>#创建Deployment控制器类型应用

kubectl apply -f deployment.yaml

#查看

kubectl get deployment

#删除,使用kubectl delete pods直接删除pod会被重新拉起

kubectl delete deployment nginx-app

#弹性伸缩

kubectl scale deployment nginx-deployment --replicas==2

3.5.1部署无状态应用(Deployment)

pod之间没有顺序所有pod共享存储pod名字包含随机数字service都有ClusterIP,可以负载均衡

kubectl apply -f deployment.yaml

kubectl expose deployment nginx-deployment --type=NodePort --target-port=80 --port=8000

示例资源清单deployment.yaml

#控制器定义

apiVersion: apps/v1

kind: Deployment #资源类型

metadata:

name: nginx-deployment

namespace: default

spec:

replicas: 1 #副本数量

selector:

matchLabels:

app: nginx

#被控制对象

template: #Pod模板

metadata: #Pod元数据

labels:

app: nginx

spec:

containers: #容器配置

- name: nginx #容器名称

image: nginx:1.18 #容器镜像

imagePullPolicy: IfNotPresent #获取镜像的策略

ports: #Pod的重启策略

- containerPort: 80 #容器需要监听的端口号

restartPolicy: Always #Pod的重启策略

3.5.2部署有状态应用(StatefulSet)

部署、扩展、更新、删除都要有顺序每个pod都有自己存储,所以都用volumeClaimTemplates,为每个pod都生成一个自己的存储,保存自己的状态pod名字始终是固定的service没有ClusterIP,是headlessservice(打通app之间的通信,而又不需要对外暴露),所以无法负载均衡,返回的都是pod名,所以pod名字都必须固定能不用StatefulSet,就不要用

示例资源清单statefulSet.yaml

#控制器定义

apiVersion: apps/v1

kind: StatefulSet #资源类型

metadata:

name: nginx-statefulset

namespace: default

spec:

serviceName: nginx

replicas: 2 #副本数量

selector:

matchLabels:

app: nginx

#被控制对象

template: #Pod模板

metadata: #Pod元数据

labels:

app: nginx

spec:

containers: #容器配置

- name: nginx #容器名称

image: nginx:1.18 #容器镜像

imagePullPolicy: IfNotPresent #获取镜像的策略

ports: #Pod的重启策略

- containerPort: 80 #容器需要监听的端口号

restartPolicy: Always #Pod的重启策略

Service资源清单service.yaml

apiVersion: v1

kind: Service #资源类型

metadata:

name: nginx

labels:

app: nginx

spec:

ports:

- port: 80

name: web

clusterIP: None

selector:

app: nginx #对应statefulSet.yaml中的spec.template.metadata.labels.app

3.6Service

作用:

防止Pod失联(服务发现)定义一组Pod访问策略(负载均衡)

service类型:

ClusterIP:默认,分配一个集群内部可以访问的虚拟ipNodePort:在每个Node上分配一个端口作为外部访问入口LoadBalancer:对外访问应用使用,比NodePort更强大,公有云实现负载均衡,控制器ExternalName:把集群外部的服务引入到集群内部中来,即实现集群内部pod和集群外部的服务进行通信

#创建应用

kubectl apply -f deployment.yaml

#创建service

#target-port指pod的端口,port指外部访问端口

kubectl expose deployment nginx-app --type=ClusterIP --target-port=80 --port=8000

#查看

kubectl get service

#删除service

kubectl delete service nginx-app

#创建NodePort类型service,使外网也能访问,在每个Node上分配一个端口作为外部访问入口

kubectl expose deployment nginx-app --type=NodePort --target-port=80 --port=8000

#kubectl get service查看service,输出如下

#NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

#kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d22h

#nginx-app NodePort 10.111.139.105 <none> 8000:31062/TCP 2s

#外网可通过任意节点的31062端口访问nginx

3.7Secret

作用:加密数据存在etcd里,让Pod容器以挂载Volume方式进行访问

kubectl apply -f secret.yaml

3.7.1secret.yaml(数据要自己base64加密)

apiVersion: v1

kind: Secret

metadata:

name: mysecret

type: Opaque

data:

username: bHp5

password: MTIzNDU2

以变量形式挂载到pod

kubectl apply -f pod.yaml

kubectl exec -it mypod bash

echo $SECRET_USERNAME

pod.yaml

apiVersion: v1

kind: Pod

metadata:

name: mypod

spec:

containers:

- name: nginx

image: nginx:1.18

imagePullPolicy: IfNotPresent

ports:

- containerPort: 80

env:

- name: SECRET_USERNAME

valueFrom:

secretKeyRef:

name: mysecret

key: username

- name: SECRET_PASSWORD

valueFrom:

secretKeyRef:

name: mysecret

key: password

3.7.2以Volume的形式挂载到Pod中

kubectl apply -f pod.yaml

kubectl exec -it mypod bash

cd /etc/foo

ls

cat username

cat password

pod.yaml

apiVersion: v1

kind: Pod

metadata:

name: mypod

spec:

containers:

- name: nginx

image: nginx:1.18

imagePullPolicy: IfNotPresent

ports:

- containerPort: 80

volumeMounts: #挂载位置

- name: foo

mountPath: "/etc/foo"

readOnly: true

volumes: #数据来源

- name: foo

secret:

secretName: mysecret

3.8ConfigMap

作用:存储不加密数据到etcd,让Pod以变量或者Volume挂载到容器中

3.8.1以变量形式挂载到pod

kubectl apply -f configMap.yaml

kubectl apply -f pod.yaml

kubectl exec -it mypod bash

echo $INFO

configMap.yaml

apiVersion: v1

kind: ConfigMap

metadata:

name: my-config

data:

config.info: info

pod.yaml

apiVersion: v1

kind: Pod

metadata:

name: mypod

spec:

containers:

- name: nginx

image: nginx:1.18

imagePullPolicy: IfNotPresent

ports:

- containerPort: 80

env:

- name: INFO

valueFrom:

configMapKeyRef:

name: my-config

key: config.info

3.8.2以volume形式挂载到Pod中

#创建ConfigMap

kubectl create configmap redis-config --from-file=redis.properties

#查看

kubectl get cm

kubectl apply -f pod.yaml

kubectl exec -it mypod bash

cat /etc/config/redis.properties

redis.properties

redis.host=127.0.0.1

redis.port=6379

redis.password=123456

pod.yaml

apiVersion: v1

kind: Pod

metadata:

name: mypod

spec:

containers:

- name: nginx

image: nginx:1.18

imagePullPolicy: IfNotPresent

ports:

- containerPort: 80

volumeMounts: #挂载位置

- name: config-volume

mountPath: "/etc/config"

readOnly: true

volumes: #数据来源

- name: config-volume

configMap:

name: redis-config

附录:yaml具体解释

# yaml格式的pod定义文件完整内容:

apiVersion: v1 #必选,版本号,例如v1

kind: Pod #必选,Pod

metadata: #必选,元数据

name: string #必选,Pod名称

namespace: string #必选,Pod所属的命名空间

labels: #自定义标签

- name: string #自定义标签名字

annotations: #自定义注释列表

- name: string

spec: #必选,Pod中容器的详细定义

containers: #必选,Pod中容器列表

- name: string #必选,容器名称

image: string #必选,容器的镜像名称

imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像

command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令

args: [string] #容器的启动命令参数列表

workingDir: string #容器的工作目录

volumeMounts: #挂载到容器内部的存储卷配置

- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名

mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符

readOnly: boolean #是否为只读模式

ports: #需要暴露的端口库号列表

- name: string #端口号名称

containerPort: int #容器需要监听的端口号

hostPort: int #容器所在主机需要监听的端口号,默认与Container相同

protocol: string #端口协议,支持TCP和UDP,默认TCP

env: #容器运行前需设置的环境变量列表

- name: string #环境变量名称

value: string #环境变量的值

resources: #资源限制和请求的设置

limits: #资源限制的设置

cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数

memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数

requests: #资源请求的设置

cpu: string #Cpu请求,容器启动的初始可用数量

memory: string #内存清楚,容器启动的初始可用数量

livenessProbe: #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可

exec: #对Pod容器内检查方式设置为exec方式

command: [string] #exec方式需要制定的命令或脚本

httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port

path: string

port: number

host: string

scheme: string

HttpHeaders:

- name: string

value: string

tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式

port: number

initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒

timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒

periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次

successThreshold: 0

failureThreshold: 0

securityContext:

privileged:false

restartPolicy: #[Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod

nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定

imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定

- name: string

hostNetwork:false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络

volumes: #在该pod上定义共享存储卷列表

- name: string #共享存储卷名称 (volumes类型有很多种)

emptyDir: { } #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值

hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录

path: string #Pod所在宿主机的目录,将被用于同期中mount的目录

secret: #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部

scretname: string

items:

- key: string

path: string

configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部

name: string

items:

- key: string



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。