Kubernetes 入门:从环境搭建到第一个 Pod 部署
一、Kubernetes 简介
Kubernetes(简称 K8s),是一个开源的容器编排平台,最初由谷歌公司开发并捐赠给云原生计算基金会(CNCF)。它的诞生旨在自动化容器化应用的部署、扩展和管理,帮助开发者和运维团队更高效地管理大规模容器化应用。
在容器技术出现之前,部署应用程序面临着诸多挑战,如环境不一致、资源管理困难等。容器技术虽然解决了应用及其依赖的打包问题,但在大规模部署和管理多个容器时,仍需要一个更强大的工具来协调和调度这些容器。Kubernetes 应运而生,它提供了一套完整的解决方案,包括资源调度、服务发现、负载均衡、自动伸缩等功能。
例如,假设我们有一个由多个微服务组成的应用,每个微服务都运行在一个容器中。使用 Kubernetes,我们可以轻松地定义这些微服务之间的依赖关系,将它们部署到不同的节点上,并根据流量自动扩展或收缩容器的数量,确保应用始终能够高效稳定地运行。
二、环境搭建
- 硬件准备 搭建 Kubernetes 环境,首先需要准备一些计算资源。你可以使用物理机,也可以使用虚拟机。如果是在本地开发环境进行实验,使用虚拟机是一个不错的选择。至少需要两台虚拟机,一台作为 Kubernetes 主节点(Master),另一台或多台作为工作节点(Worker)。
每台机器的硬件配置建议如下:
- CPU:至少 2 核
- 内存:至少 2GB
- 磁盘空间:至少 20GB
以 VMware Workstation 为例,创建虚拟机时,选择合适的操作系统(如 Ubuntu 20.04,这是一个广泛使用且对 Kubernetes 支持较好的 Linux 发行版),并按照上述硬件配置进行设置。
- 操作系统配置 在每台机器上安装好操作系统后,还需要进行一些基础配置。
- 更新系统软件包:
sudo apt update
sudo apt upgrade -y
- 关闭交换空间:Kubernetes 不支持在启用交换空间的节点上运行,关闭交换空间可以通过以下命令:
sudo swapoff -a
并编辑 /etc/fstab
文件,注释掉交换分区的相关行,确保系统重启后交换空间不会自动启用。
- 配置内核参数:为了让 Kubernetes 网络功能正常工作,需要配置一些内核参数。编辑
/etc/sysctl.conf
文件,添加以下内容:
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
然后执行 sudo sysctl -p
使配置生效。
- 安装 Docker Kubernetes 依赖 Docker 作为容器运行时。在每台机器上安装 Docker,可以使用以下步骤:
- 添加 Docker 官方 GPG 密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
- 添加 Docker 软件源:
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- 安装 Docker:
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y
- 配置 Docker 开机自启并启动 Docker 服务:
sudo systemctl enable docker
sudo systemctl start docker
- 安装 kubeadm、kubelet 和 kubectl 这三个组件是搭建 Kubernetes 环境的核心工具。
- 添加 Kubernetes 软件源:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
- 安装 kubeadm、kubelet 和 kubectl:
sudo apt update
sudo apt install kubeadm=1.23.5-00 kubelet=1.23.5-00 kubectl=1.23.5-00 -y
这里指定了版本号 1.23.5
,你可以根据实际情况选择合适的版本。
- 配置 kubelet 开机自启:
sudo systemctl enable kubelet
三、初始化 Kubernetes 主节点
- 使用 kubeadm 初始化主节点 在主节点上,执行以下命令初始化 Kubernetes 集群:
sudo kubeadm init --apiserver-advertise-address=主节点的IP地址 --pod-network-cidr=10.244.0.0/16
其中,--apiserver-advertise-address
参数指定主节点的 IP 地址,--pod-network-cidr
参数指定 Pod 网络的地址范围。
初始化过程可能会持续几分钟,期间会下载所需的镜像并进行各种配置。如果初始化成功,你会看到类似以下的输出:
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 主节点的IP地址:6443 --token [token] \
--discovery-token-ca-cert-hash [hash]
- 配置 kubectl
根据上面输出的提示,对于普通用户,执行以下命令配置
kubectl
:
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
- 安装网络插件 Kubernetes 本身不提供网络功能,需要安装一个网络插件来实现 Pod 之间的通信。这里以 Weave Net 为例,执行以下命令安装:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
安装完成后,可以通过 kubectl get pods -n kube-system
命令查看网络插件相关的 Pod 是否正常运行。
四、加入工作节点到集群
- 获取加入命令
在主节点上,执行
kubeadm token create --print-join-command
命令获取工作节点加入集群的命令。命令格式如下:
kubeadm join 主节点的IP地址:6443 --token [token] \
--discovery-token-ca-cert-hash [hash]
- 在工作节点上执行加入命令 在每个工作节点上,以 root 用户身份执行上述获取到的加入命令。执行成功后,工作节点就会加入到 Kubernetes 集群中。
可以在主节点上通过 kubectl get nodes
命令查看集群中的节点状态,确保所有节点都处于 Ready
状态。
五、理解 Pod
- Pod 的概念 Pod 是 Kubernetes 中最小的可部署和可管理的计算单元。一个 Pod 可以包含一个或多个紧密相关的容器,这些容器共享网络命名空间、存储卷等资源。
例如,假设我们有一个 Web 应用,它由一个后端 API 容器和一个前端静态文件服务器容器组成。我们可以将这两个容器放在同一个 Pod 中,它们可以通过 localhost
进行通信,并且共享相同的网络和存储资源。
-
Pod 的生命周期 Pod 的生命周期包括创建、运行、失败和终止等阶段。当我们创建一个 Pod 时,Kubernetes 会根据 Pod 的定义在集群中选择一个合适的节点来运行它。如果 Pod 中的容器运行失败,Kubernetes 可以根据配置自动重启容器。当我们删除 Pod 时,Kubernetes 会逐步终止其中的容器。
-
Pod 的资源管理 在定义 Pod 时,可以为容器指定所需的资源,如 CPU 和内存。例如,以下是一个简单的 Pod 定义文件,其中为容器指定了 CPU 和内存限制:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx:1.19.10
resources:
requests:
cpu: "250m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "128Mi"
这里,requests
表示容器请求的资源量,limits
表示容器允许使用的最大资源量。250m
表示 250 毫核 CPU,64Mi
表示 64 兆字节内存。
六、创建和部署第一个 Pod
- 编写 Pod 定义文件
使用文本编辑器创建一个名为
my - pod.yaml
的文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: my - first - pod
spec:
containers:
- name: my - container
image: nginx:1.19.10
ports:
- containerPort: 80
在这个定义文件中,我们定义了一个名为 my - first - pod
的 Pod,其中包含一个名为 my - container
的容器,使用的镜像为 nginx:1.19.10
,并暴露容器的 80 端口。
- 部署 Pod
在保存好
my - pod.yaml
文件后,在主节点上执行以下命令部署 Pod:
kubectl apply -f my - pod.yaml
执行成功后,可以通过 kubectl get pods
命令查看 Pod 的状态,确保其处于 Running
状态。
- 访问 Pod 由于 Pod 中的容器运行在集群内部网络中,要从外部访问它,需要使用服务(Service)。这里先介绍一种简单的方式,通过端口转发来访问。执行以下命令:
kubectl port - forward my - first - pod 8080:80
这将把本地的 8080 端口转发到 Pod 的 80 端口。此时,在浏览器中访问 http://localhost:8080
,就可以看到 Nginx 的欢迎页面,说明我们的第一个 Pod 部署成功并可以正常访问。
七、Pod 的管理与维护
-
查看 Pod 详细信息 可以使用
kubectl describe pod my - first - pod
命令查看 Pod 的详细信息,包括容器状态、资源使用情况、事件记录等。这对于调试和了解 Pod 的运行情况非常有帮助。 -
删除 Pod 如果需要删除 Pod,可以执行
kubectl delete pod my - first - pod
命令。Pod 删除后,其中的容器也会被终止。 -
更新 Pod 如果需要更新 Pod 中的容器镜像,可以修改
my - pod.yaml
文件中的镜像版本,然后执行kubectl apply -f my - pod.yaml
命令。Kubernetes 会自动更新 Pod,将容器替换为新的镜像版本。
八、深入 Pod 调度
- 节点选择器(NodeSelector) 默认情况下,Kubernetes 会根据节点的资源情况自动选择一个节点来运行 Pod。但有时候我们可能希望将 Pod 调度到特定的节点上,这时可以使用节点选择器。
首先,在节点上添加标签,例如,在某个节点上执行以下命令添加一个 disktype=ssd
的标签:
kubectl label nodes 节点名称 disktype=ssd
然后,在 Pod 定义文件中使用节点选择器:
apiVersion: v1
kind: Pod
metadata:
name: my - pod - with - selector
spec:
nodeSelector:
disktype: ssd
containers:
- name: my - container
image: nginx:1.19.10
这样,这个 Pod 就只会被调度到具有 disktype=ssd
标签的节点上。
- 亲和性与反亲和性(Affinity and Anti - Affinity) 亲和性与反亲和性提供了更灵活的 Pod 调度策略。
- 亲和性:可以定义 Pod 与节点或其他 Pod 之间的亲和关系,使得 Pod 更倾向于被调度到特定的节点或与特定的 Pod 运行在同一节点上。
- 反亲和性:与亲和性相反,定义 Pod 与节点或其他 Pod 之间的反亲和关系,使得 Pod 避免被调度到特定的节点或与特定的 Pod 运行在同一节点上。
例如,以下是一个使用节点亲和性的 Pod 定义:
apiVersion: v1
kind: Pod
metadata:
name: my - pod - with - affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: my - container
image: nginx:1.19.10
这里使用 requiredDuringSchedulingIgnoredDuringExecution
表示在调度时必须满足亲和性条件,matchExpressions
中定义了匹配规则。
九、Pod 的存储
-
Volume 简介 在 Pod 中,容器的数据默认是存储在容器的文件系统中,当容器重启或删除时,数据会丢失。为了持久化存储数据,可以使用 Kubernetes 的 Volume。Volume 是 Pod 中可以被多个容器挂载的目录。
-
EmptyDir Volume EmptyDir Volume 是最基本的 Volume 类型,它在 Pod 创建时被创建,在 Pod 删除时被删除。它的生命周期与 Pod 相同,并且数据只存储在节点的本地磁盘上。
以下是一个使用 EmptyDir Volume 的 Pod 定义:
apiVersion: v1
kind: Pod
metadata:
name: my - pod - with - emptydir
spec:
containers:
- name: write - container
image: busybox
command: ["sh", "-c", "while true; do echo $(date) >> /data/out.txt; sleep 1; done"]
volumeMounts:
- name: my - emptydir
mountPath: /data
- name: read - container
image: busybox
command: ["sh", "-c", "while true; do cat /data/out.txt; sleep 1; done"]
volumeMounts:
- name: my - emptydir
mountPath: /data
volumes:
- name: my - emptydir
emptyDir: {}
在这个例子中,write - container
容器不断将时间写入 /data/out.txt
文件,read - container
容器不断读取这个文件。两个容器通过共享 my - emptydir
Volume 实现数据共享。
- PersistentVolume 和 PersistentVolumeClaim 对于需要持久化存储且不依赖于特定节点的场景,可以使用 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)。
- PersistentVolume:是集群中管理员预先创建的存储资源,它可以是网络存储(如 NFS、Ceph 等)或本地存储。
- PersistentVolumeClaim:是用户对存储资源的请求,Kubernetes 会根据 PVC 的要求自动绑定合适的 PV。
以下是一个简单的 PV 和 PVC 示例: 定义 PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: my - pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.1.100
path: /exports/k8s - pv
这里定义了一个 1GB 的 PV,使用 NFS 作为存储后端。
定义 PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my - pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
这个 PVC 请求 500MB 的存储空间。
在 Pod 中使用 PVC:
apiVersion: v1
kind: Pod
metadata:
name: my - pod - with - pvc
spec:
containers:
- name: my - container
image: nginx:1.19.10
volumeMounts:
- name: my - volume
mountPath: /usr/share/nginx/html
volumes:
- name: my - volume
persistentVolumeClaim:
claimName: my - pvc
这样,Pod 就可以使用 PVC 绑定的 PV 提供的存储。
通过以上步骤,你已经完成了从 Kubernetes 环境搭建到第一个 Pod 部署以及相关深入知识的学习。在实际应用中,还需要不断探索和实践,以充分发挥 Kubernetes 的强大功能,构建高效稳定的容器化应用。