MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kubernetes 入门:从环境搭建到第一个 Pod 部署

2022-02-161.8k 阅读

一、Kubernetes 简介

Kubernetes(简称 K8s),是一个开源的容器编排平台,最初由谷歌公司开发并捐赠给云原生计算基金会(CNCF)。它的诞生旨在自动化容器化应用的部署、扩展和管理,帮助开发者和运维团队更高效地管理大规模容器化应用。

在容器技术出现之前,部署应用程序面临着诸多挑战,如环境不一致、资源管理困难等。容器技术虽然解决了应用及其依赖的打包问题,但在大规模部署和管理多个容器时,仍需要一个更强大的工具来协调和调度这些容器。Kubernetes 应运而生,它提供了一套完整的解决方案,包括资源调度、服务发现、负载均衡、自动伸缩等功能。

例如,假设我们有一个由多个微服务组成的应用,每个微服务都运行在一个容器中。使用 Kubernetes,我们可以轻松地定义这些微服务之间的依赖关系,将它们部署到不同的节点上,并根据流量自动扩展或收缩容器的数量,确保应用始终能够高效稳定地运行。

二、环境搭建

  1. 硬件准备 搭建 Kubernetes 环境,首先需要准备一些计算资源。你可以使用物理机,也可以使用虚拟机。如果是在本地开发环境进行实验,使用虚拟机是一个不错的选择。至少需要两台虚拟机,一台作为 Kubernetes 主节点(Master),另一台或多台作为工作节点(Worker)。

每台机器的硬件配置建议如下:

  • CPU:至少 2 核
  • 内存:至少 2GB
  • 磁盘空间:至少 20GB

以 VMware Workstation 为例,创建虚拟机时,选择合适的操作系统(如 Ubuntu 20.04,这是一个广泛使用且对 Kubernetes 支持较好的 Linux 发行版),并按照上述硬件配置进行设置。

  1. 操作系统配置 在每台机器上安装好操作系统后,还需要进行一些基础配置。
  • 更新系统软件包
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 使配置生效。

  1. 安装 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
  1. 安装 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 主节点

  1. 使用 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]
  1. 配置 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
  1. 安装网络插件 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 是否正常运行。

四、加入工作节点到集群

  1. 获取加入命令 在主节点上,执行 kubeadm token create --print-join-command 命令获取工作节点加入集群的命令。命令格式如下:
kubeadm join 主节点的IP地址:6443 --token [token] \
        --discovery-token-ca-cert-hash [hash]
  1. 在工作节点上执行加入命令 在每个工作节点上,以 root 用户身份执行上述获取到的加入命令。执行成功后,工作节点就会加入到 Kubernetes 集群中。

可以在主节点上通过 kubectl get nodes 命令查看集群中的节点状态,确保所有节点都处于 Ready 状态。

五、理解 Pod

  1. Pod 的概念 Pod 是 Kubernetes 中最小的可部署和可管理的计算单元。一个 Pod 可以包含一个或多个紧密相关的容器,这些容器共享网络命名空间、存储卷等资源。

例如,假设我们有一个 Web 应用,它由一个后端 API 容器和一个前端静态文件服务器容器组成。我们可以将这两个容器放在同一个 Pod 中,它们可以通过 localhost 进行通信,并且共享相同的网络和存储资源。

  1. Pod 的生命周期 Pod 的生命周期包括创建、运行、失败和终止等阶段。当我们创建一个 Pod 时,Kubernetes 会根据 Pod 的定义在集群中选择一个合适的节点来运行它。如果 Pod 中的容器运行失败,Kubernetes 可以根据配置自动重启容器。当我们删除 Pod 时,Kubernetes 会逐步终止其中的容器。

  2. 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

  1. 编写 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 端口。

  1. 部署 Pod 在保存好 my - pod.yaml 文件后,在主节点上执行以下命令部署 Pod:
kubectl apply -f my - pod.yaml

执行成功后,可以通过 kubectl get pods 命令查看 Pod 的状态,确保其处于 Running 状态。

  1. 访问 Pod 由于 Pod 中的容器运行在集群内部网络中,要从外部访问它,需要使用服务(Service)。这里先介绍一种简单的方式,通过端口转发来访问。执行以下命令:
kubectl port - forward my - first - pod 8080:80

这将把本地的 8080 端口转发到 Pod 的 80 端口。此时,在浏览器中访问 http://localhost:8080,就可以看到 Nginx 的欢迎页面,说明我们的第一个 Pod 部署成功并可以正常访问。

七、Pod 的管理与维护

  1. 查看 Pod 详细信息 可以使用 kubectl describe pod my - first - pod 命令查看 Pod 的详细信息,包括容器状态、资源使用情况、事件记录等。这对于调试和了解 Pod 的运行情况非常有帮助。

  2. 删除 Pod 如果需要删除 Pod,可以执行 kubectl delete pod my - first - pod 命令。Pod 删除后,其中的容器也会被终止。

  3. 更新 Pod 如果需要更新 Pod 中的容器镜像,可以修改 my - pod.yaml 文件中的镜像版本,然后执行 kubectl apply -f my - pod.yaml 命令。Kubernetes 会自动更新 Pod,将容器替换为新的镜像版本。

八、深入 Pod 调度

  1. 节点选择器(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 标签的节点上。

  1. 亲和性与反亲和性(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 的存储

  1. Volume 简介 在 Pod 中,容器的数据默认是存储在容器的文件系统中,当容器重启或删除时,数据会丢失。为了持久化存储数据,可以使用 Kubernetes 的 Volume。Volume 是 Pod 中可以被多个容器挂载的目录。

  2. 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 实现数据共享。

  1. 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 的强大功能,构建高效稳定的容器化应用。