k8s 自动化部署尝鲜,作为一个后端开发,还是多少要掌握一些运维知识的,但是不用掌握这么多~~
每台机器都配置
三台Ubuntu18.04虚拟机:
192.168.163.128 master1
192.168.163.129 node1
192.168.163.131 node2
每个节点都需要具有可以通讯的唯一的静态 IP 地址,以便其他节点和控制平面能够正常与其通信,静态 IP 地址还是实现负载均衡和服务发现的重要条件。
为了避免DNS解析出现问题,通常会将上述ip和主机名写入每个节点的/etc/hosts文件中。
# 关闭防火墙和防火墙开机自启
ufw disable
systemctl stop ufw
systemctl disable ufw
#关闭swap分区(一次有效)
sudo swapoff -a
#永久关闭swap分区(推荐)注释fstab文件中swap那一行
vim /etc/fstab
# /swapfile none swap sw 0 0
每台机器上都需要安装
#1.更新apt软件包列表
apt update
#2.安装依赖项
# apt-transport-https 提供使用https协议进行apt软件仓库访问支持
# ca-certificates 保证与网络服务器之间的通信是安全和可靠的
# curl 用来下载文件密钥
# software-properties-common 管理第三方软件源
# openssh-server 允许用户从远程计算机连接到本地主机
apt install apt-transport-https ca-certificates curl software-properties-common openssh-server
#3.下载Docker在Ubuntu系统上的apt-key公钥,并将其添加到本地系统
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
#4.在Ubuntu操作系统中添加Docker软件包安装源(repository)并更新apt
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
apt update
#5.显示Docker软件包的安装状态和可用版本
apt-cache policy docker-ce
#6.在Ubuntu操作系统中安装指定版本的Docker软件包
apt install docker-ce=5:20.10.10~3-0~ubuntu-bionic
#7.查看状态
systemctl status docker
安装之后修改docker的cgroup驱动为systemd,否则执行kubeadm init和kubeadm join时会出现[WARNING IsDockerSystemdCheck]: detected “cgroupfs” as the Docker cgroup driver. The recommended driver is “systemd”.警告
vim /lib/systemd/system/docker.service
# 找到文件中下面位置
···
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
···
# 修改第三行,指定cgroup驱动
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd
# 重启docker
systemctl daemon-reload
systemctl restart docker
# 查看cgroup驱动和docker服务状态
docker info | grep -i cgroup
systemctl status docker
#结果
root@master1:/# docker info | grep -i cgroup
WARNING: No swap limit support
Cgroup Driver: systemd
Cgroup Version: 1
root@master1:/# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset:
Active: active (running) since Tue 2023-05-23 08:55:38 CST; 3 days ago
Docs: https://docs.docker.com
Main PID: 2096 (dockerd)
Tasks: 26
CGroup: /system.slice/docker.service
└─2096 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/contai
······
每台机器都需要安装
# 下载 Kubernetes APT 软件源的 GPG 密钥
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
# 然后在/etc/apt/sources.list.d下新建文件kubernetes.list,添加一个 Kubernetes 的软件源并更新apt
vim /etc/apt/sources.list.d/kubernetes.list
写入 deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
apt update
#下载安装组件
apt-get install -y kubelet=1.23.2-00 kubeadm=1.23.2-00 kubectl=1.23.2-00
组件介绍:
# 可以查看初始化平台需要的镜像列表:
kubeadm config images list
# 使用kubeadm控制平台初始化
kubeadm init \
--image-repository=registry.aliyuncs.com/google_containers \ #指定容器镜像的仓库地址
--pod-network-cidr=10.244.0.0/16 \ #指定容器网络的 IP 地址段(CIDR),默认为 10.244.0.0/16
--kubernetes-version=v1.23.2 \ #指定k8s版本,不指定默认为最新版,最好与组件版本一致
--control-plane-endpoint=192.168.163.128:6443 \ #指定 Kubernetes 控制平面组件的访问地址,默认为 API Server 的地址
--apiserver-advertise-address=192.168.163.128 # 指定 Kubernetes API Server 的 IP 地址或主机名,默认为当前节点的 IP 地址
# 初始化完成之后会输出如下命令,可以在node节点运行加入集群。
kubeadm join 192.168.163.128:6443 --token xzerjg.uynhtwz5og88szo0 \
--discovery-token-ca-cert-hash sha256:f4b3a0f29f8f7fa1c9c1dacfa68124f0395ccba8a1e9dfc3dae98b836292e795
# 设置 KUBECONFIG 环境变量的值,以便让 Kubernetes 命令行工具(kubectl)知道如何连接 Kubernetes 集群
#非root用户执行:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# root用户执行:
export KUBECONFIG=/etc/kubernetes/admin.conf(仅本次有效)
# 或永久设置:
vim /etc/profile
#文件末尾添加
export KUBECONFIG=/etc/kubernetes/admin.conf
# 启动kubelet 设置为开机自启动
systemctl enable kubelet
# 启动k8s服务程序
systemctl start kubelet
# 启动完成后查看节点(未设置KUBECONFIG则运行不了kubectl)
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 NotReady control-plane,master 10m v1.23.2
# 查看组件状态
kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
上述查询组件状态中scheduler和controller-manager状态为unhealthy,可以注释掉/etc/kubernetes/manifests下的kube-controller-manager.yaml和kube-scheduler.yaml的- --port=0解决。
# 启动kubelet 设置为开机自启动
systemctl enable kubelet
# 执行平台初始化时输出的命令即可
kubeadm join 192.168.163.128:6443 --token xzerjg.uynhtwz5og88szo0 \
--discovery-token-ca-cert-hash sha256:f4b3a0f29f8f7fa1c9c1dacfa68124f0395ccba8a1e9dfc3dae98b836292e795
#若上述命令失效,可以在master节点上执行下述命令重新输出
kubeadm token create --print-join-command --ttl 24h
# 加入后在master查看节点
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 UnReady control-plane,master 32m v1.23.2
node1 UnReady <none> 23m v1.23.2
node2 UnReady <none> 21m v1.23.2
# 由于直接下载会被墙,所以先在/etc/hosts文件添加一条
199.232.68.133 raw.githubusercontent.com
# 然后通过wget下载fannel配置文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
#下载完之后执行
kubectl apply -f kube-flannel.yml
# 等待创建完之后查看节点可以看到状态都变为ready
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready control-plane,master 37m v1.23.2
node1 Ready <none> 28m v1.23.2
node2 Ready <none> 26m v1.23.2
ok,k8s一主两从部署完成!
#下载dashboard的yaml文件
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
#修改yaml
# type 被设置为 NodePort 类型,表示这个 Service 将会使用 NodePort 的方式对外暴露服务,可以从外部访问
# nodePort 属性用于指定 Service 暴露的 NodePort 端口号,它允许外部网络从集群节点的 IP 地址和该端口号来访问这个 Service
vim recommended.yaml
---------------
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30001
type: NodePort
selector:
k8s-app: kubernetes-dashboard
-------------------
#使用kubectl进行创建
kubectl apply -f recommended.yaml
#使用kubectl查看dashboard的pod和serviced状态
kubectl get pods -n kubernetes-dashboard
kubectl get pods,svc -n kubernetes-dashboard
# 创建用户
kubectl create serviceaccount dashboard-admin -n kube-system
# 用户授权
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 获取用户Token
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
#打开web: 可以通过上面的token登录
https://192.168.163.128:30001
kubernetes,是一个全新的基于容器技术的分布式架构领先方案,本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
● 自我修复:一旦某一个容器崩溃,能够迅速启动新的容器
● 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
● 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
● 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
● 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
● 存储编排:可以根据容器自身的需求自动创建存储卷
ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
Etcd :负责存储集群中各种资源对象的信息
Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
KubeProxy : 负责提供集群内部的服务发现和负载均衡
Docker : 负责节点上容器的各种操作
思路概述:准备了一个简单的springboot项目,不连数据库;
k8s作为一个容器编排方案,应用程序在其中是作为一个容器进行的,而容器需要存放在pod中受k8s的调度和控制,所以需要将项目打包成镜像便于创建pod时指定;
创建和管理pod需要pod控制器,所以选择创建一个pod控制器,我的springboot项目作为一个无状态的应用程序,最好使用Deployment控制器来创建pod;
程序运行起来之后肯定需要集群外部进行访问,所以需要往外暴露接口,这时候就需要创建service来将应用端口暴露给外部便于访问。
# master节点创建目录存储jar包
root@master1:/home/master1/javapj# ls
javaproject.jar
# 在该目录下创建Dockerfile文件,内容如下
FROM openjdk:8-jdk-alpine
VOLUME /tmp
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ADD javaproject.jar javaproject.jar
ENTRYPOINT ["java","-jar","/javaproject.jar", "&"]
#执行build命令打包镜像
docker build -t javademo:v1 .
# 查看镜像
root@master1:/home/master1/javapj# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
javademo v1 3d10dac890bc 56 seconds ago 122MB
apiVersion: v1
kind: Namespace
metadata:
name: javademo
labels:
app: javademo
apiVersion: apps/v1
kind: Deployment
metadata:
name: javademo1
namespace: javademo #指定命名空间
labels:
app: javademo1
spec:
replicas: 1 #指定副本数量
template:
metadata:
name: javademo1
labels:
app: javademo1
spec:
containers:
- name: javademo1
image: javademo:v1 #指定镜像
imagePullPolicy: Never #重启镜像拉取策略,由于是自己打包的镜像,所以就不拉取了
ports:
- containerPort: 8111 #容器暴露的端口
restartPolicy: Always #重启pod的策略,只要低于指定的数量就会重启
selector:
matchLabels:
app: javademo1
3.创建service去暴露端口
apiVersion: v1
kind: Service
metadata:
name: javademo1-svc
namespace: javademo
spec:
selector:
app: javademo1
ports:
- port: 8111
targetPort: 8111
nodePort: 30033 #通过30033端口被外部访问
type: NodePort #NodePort可以被外部访问
三个port的区别:
nodeNort是服务对象公开的端口号,可以从群集外部访问该端口。当服务对象暴露了 Node Port 时,Kubernetes 将自动分配一个高位端口,并将其映射到集群中的每个节点上。然后,可以通过任何节点的 IP 地址和分配的 Node Port 访问该服务。
port是容器内部使用的端口号,是应用程序绑定的端口。该端口只存在于容器内部,外部无法直接访问该端口。当容器暴露了该端口时,可以通过服务对象让集群内的其他组件访问该端口。
targetPort是服务对象与 Pod 通信时使用的端口号。当服务对象与 Pod 通过选择器匹配关联时,服务对象将流量转发到 Pod 的 Target Port 上,而非容器的端口。Pod 可以选择任何可用端口作为 Target Port,但通常情况下都会选择与容器端口相同的端口号。
创建资源的方式有两种:
部署好之后,通过http://192.168.163.128:30033/、http://192.168.163.128:30033、http://192.168.163.128:30033/均可访问该服务。
节点级别的资源限制:通过 Node 上的配置文件或者命令行参数,可以对节点上运行的所有 Pod 进行资源限制。例如,使用 kubelet 在启动每个节点时添加 --cpu-manager-policy=static 参数,即可限制该节点上所有 Pod 的 CPU 使用量。
可以通过 LimitRange 和 ResourceQuota 两个对象来限制命名空间级别的cpu,内存,存储,显卡等资源:
#使用LimitRange限制每个容器的最大和最小占用资源
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-mem-limit-range
namespace: namespace-name
spec:
limits:
- type: Container
max:
cpu: "500m"
memory: "128Mi"
min:
cpu: "100m"
memory: "64Mi"
#使用ResourceQuota限制整个命名空间下所有pod和容器的资源总量
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-mem-quota
namespace: namespace-name
spec:
hard:
requests.cpu: "2"
requests.memory: "512Mi"
#使用LimitRange 对象将一个命名空间中所有容器的存储资源限制为 1GB
apiVersion: v1
kind: LimitRange
metadata:
name: storage-limit-range
namespace: namespace-name
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: "1Gi"
#使用ResourceQuota对象将一个命名空间中所有Pod和容器的存储资源使用限制为总共不超过 5GB:
apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-quota
spec:
hard:
requests.storage: "5Gi"
#在 Kubernetes 1.19 版本及以上,可以使用 DeviceTopology API 来限制一个 Namespace 中
#所有 Pod 和容器的显卡资源使用。例如,以下 YAML 文件中的 LimitRange 对象将一个命名空间
#中所有容器的显卡资源限制为最多只能绑定 2 个报文设备(RDMA)和 1 个 NVIDIA GPU 设备
apiVersion: v1
kind: LimitRange
metadata:
name: gpu-limit-range
spec:
limits:
- type: nvidia.com/gpu
max:
nvidia.com/gpu: "1"
- type: "openshift.io/network"
max:
"rdma/ib": "2"
#注意,上述显卡资源限制需要基于支持 DeviceTopology API 的 CRI 实现,
#例如 cri-o、containerd 等。如果使用的是 Docker CRI 实现,则需要额外
#安装 nvidia-docker2 插件来实现显卡资源限制
# 在Deployment中的spec.container[].resources中限制每个容器的cpu和内存
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: namespace-name
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx
resources:
limits:
cpu: "0.5"
memory: "128Mi"
requests:
cpu: "0.25"
memory: "64Mi"
#或者直接限制一个pod中所有容器能使用的资源
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: namespace-name
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: container-1
image: nginx
- name: container-2
image: redis
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
#也可以在k8s集群中安装DevicePlugins 插件用来暴露设备资源,
#暴露之后就可以在spec.container[].resources中定义容器的资源请求和限制,包括显卡资源
#比如下面为容器请求一个 NVIDIA GPU 资源,并限制其最大使用数量为 1
apiVersion: v1
kind: Pod
metadata:
name: my-pod
namespace: namespace-name
spec:
containers:
- name: my-container
image: my-image
resources:
limits:
nvidia.com/gpu: 1