20260624 k8s pod命令

Kubernetes Pod

学习参考:Pod

环境准备

bash 复制代码
[root@master30 ~]# kubectl create ns pods
[root@master30 ~]# kubectl config set-context --current --namespace pods

Pod 介绍

pod 代表一个deployment单元:a single instance of an application in Kubernetes。

k8s通过定义一个Pod的资源,然后在Pod里面运行容器,容器需要指定镜像,用来运行具体的服务。Pod代表集群上正在运行的一个进程,一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,应该把整个pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。

  • 运行单个容器的 Pod:将Pod看作是单个容器的包装器,kubernetes管理pods而不是直接管理容器。

  • 运行多个容器的 Pod :POD可以封装一个由多个共存容器组成的应用程序。pod中的容器会自动在集群中的同一物理机或虚拟机上运行。POD中多个容器共享资源和依赖项,彼此通信,以及协调何时以及如何终止它们。POD将这些容器、网络资源和存储资源作为一个单一的可管理实体包装在一起。pod中多个容器共享网络和存储资源。每个pod分配唯一的ip地址,pod中容器共享netns,包括ip地址和port端口。多个容器之间使用localhost通信。当pod中容器与其他pod通信,需要使用共享的网络资源。pod可以使用多个volume,pod中所有容器都可以访问这些卷。

白话解释: 可以把pod看成是一个"豌豆荚",里面有很多"豆子"(容器)。一个豌豆荚里的豆子,它们吸收着共同的营养成分、肥料、水分等,Pod和容器的关系也是一样,Pod里面的容器共享pod的网络、存储等。

例如:web容器提供文件共享,另外一个容器负责更新文件内容。

pod 基本管理

创建 pod

bash 复制代码
# 空运行,只生成yaml文件
[root@master30 ~]# kubectl run web --image=hub.laoma.cloud/library/nginx --dry-run=client -o yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: web
  name: web
spec:
  containers:
  - image: hub.laoma.cloud/library/nginx
    name: web
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
bash 复制代码
# 直接创建pod
[root@master30 ~]# kubectl run web --image=hub.laoma.cloud/library/nginx
pod/web created

[root@master30 ~]# kubectl get pod
NAME   READY   STATUS              RESTARTS   AGE
web    0/1     ContainerCreating   0          36s

[root@master30 ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          51s

[root@master30 ~]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE               NOMINATED NODE   READINESS GATES
web    1/1     Running   0          67s   10.224.51.131   worker31.laoma.cloud   <none>           <none>

[root@master30 ~]# ssh root@worker31 nerdctl ps --namespace k8s.io |grep web
[root@master30 ~]# ssh root@worker31 nerdctl images --namespace k8s.io |grep nginx

查看 pod

bash 复制代码
# 以yaml格式查看pod
[root@master30 ~]# kubectl get pod web -o yaml

# 查看pod
[root@master30 ~]# kubectl describe pod web

# 查看pod标准输出,可以是哟个选项-f动态查看pod输出
[root@master30 ~]# kubectl logs -f web 

编辑 pod

bash 复制代码
[root@master30 ~]# kubectl edit pod web

提示:并不是所有属性都可以编辑,例如pod名称。如果非要编辑特定属性,可以先删除pod,然后修改pod对的yaml文件,重新创建。

pod 中执行命令

bash 复制代码
[root@master30 ~]# kubectl exec web -- hostname
web
[root@master30 ~]# kubectl exec web -- pwd
/
[root@master30 ~]# kubectl exec -it web -- bash -c 'echo Hello World > htdocs/index.html'
[root@master30 ~]# kubectl exec web -- id
uid=0(root) gid=0(root) groups=0(root)

cp 文件给 pod

bash 复制代码
[root@master30 ~]# kubectl cp /etc/hosts web:/new-hosts
[root@master30 ~]# kubectl exec web -- ls /new-hosts
/new-hosts

删除 pod

bash 复制代码
[root@master30 ~]# kubectl delete pod web
pod "web" deleted

删除时间

bash 复制代码
[root@master30 ~]# kubectl get pod web -o yaml|grep ' terminationGracePeriodSeconds'
terminationGracePeriodSeconds: 30

yaml 文件创建 pod

yaml 复制代码
# web.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: hub.laoma.cloud/library/nginx
    name: web
bash 复制代码
[root@master30 ~]# kubectl create -f web.yaml
# 或者
[root@master30 ~]# kubectl apply -f web.yaml

综合实验:构建 wordpreess

  1. 创建 pod-mysql 数据库
  2. 创建 pod-wordpress 博客

参考步骤:

bash 复制代码
# 创建 pod-mysql 数据库
[root@master30 ~]# kubectl run wordpress-db --image=hub.laoma.cloud/library/mysql --image-pull-policy IfNotPresent --env MYSQL_ROOT_PASSWORD=123

# 创建 pod-wordpress 博客
[root@master30 ~]# kubectl run wordpress-app --image=hub.laoma.cloud/library/wordpress --image-pull-policy IfNotPresent

# 实现集群外访问集群内pod
[root@master30 ~]# kubectl port-forward pod/wordpress-app --address 10.1.8.30 8080:80
# 该命令窗口不要关闭

# 查看 IP
[root@master30 ~]# kubectl get pods -o wide | awk '{print $1" "$6}'
NAME IP
wordpress-app 10.224.113.135
wordpress-db 10.224.19.5

# 创建数据库
[root@master30 ~]# mysql -uroot -p123 -h 10.224.19.5
mysql> create database wordpress;
mysql> create user wordpress identified by '123';
mysql> grant all privileges on wordpress.* to wordpress;
mysql> flush privileges;
mysql> exit

访问web页面 http://10.1.8.30:8080,配置站点。

多容器 pod

示例文件:blog.yaml

bash 复制代码
[root@master30 ~]# vim pod-blog.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: bbs
  labels:
    run: bbs
spec:
  containers:
  - image: hub.laoma.cloud/library/mysql:latest
    imagePullPolicy: IfNotPresent
    name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "123"
    - name: MYSQL_USER
      value: tom
    - name: MYSQL_PASSWORD
      value: "123"
    - name: MYSQL_DATABASE
      value: bbs
    ports:
    - containerPort: 3306
      name: mysql
      protocol: TCP
  - image: hub.laoma.cloud/library/wordpress:latest
    imagePullPolicy: IfNotPresent
    name: wordpress
    env:
    - name: WORDPRESS_DB_USER
      value: tom
    - name: WORDPRESS_DB_PASSWORD
      value: "123"
    - name: WORDPRESS_DB_NAME
      value: bbs
    - name: WORDPRESS_DB_HOST
      value: 127.0.0.1
    ports:
    - containerPort: 80
      name: wordpress
      protocol: TCP
      hostPort: 80
bash 复制代码
[root@master30 ~]# kubectl apply -f pod-blog.yaml

# 查看 pod 运行节点
[root@master30 ~]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE               NOMINATED NODE   READINESS GATES
bbs    2/2     Running   0          10m   10.224.225.68   worker32.laoma.cloud   <none>           <none>

# 多容器pod中执行命令,通过-c指定容器
[root@master30 ~]# kubectl exec bbs -c wordpress -- hostname
bbs
[root@master30 ~]# kubectl cp /etc/hosts bbs:/new-hosts -c wordpress
[root@master30 ~]# kubectl exec bbs -c wordpress -- ls /new-hosts
/new-hosts

数据库访问测试

bash 复制代码
[root@master30 ~]# kubectl exec -it bbs -c mysql -- mysql -utom -p123
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

使用所在宿主机的80端口访问:http://10.1.8.32/

pod 关键属性

bash 复制代码
[root@master30 ~]# kubectl explain pod | grep '^  [a-zA-Z]'
  apiVersion	<string>
  kind	<string>
  metadata	<ObjectMeta>
  spec	<PodSpec>
  status	<PodStatus>

pod.metadata

bash 复制代码
[root@master30 ~]# kubectl explain pod.metadata | grep '^  [a-zA-Z]'
   annotations	<map[string]string>
   clusterName	<string>
   creationTimestamp	<string>
   deletionGracePeriodSeconds	<integer>
   deletionTimestamp	<string>
   finalizers	<[]string>
   generateName	<string>
   generation	<integer>
   labels	<map[string]string>
   managedFields	<[]Object>
   name	<string>
   namespace	<string>
   ownerReferences	<[]Object>
   resourceVersion	<string>
   selfLink	<string>
   uid	<string>

需要关注的属性:labels,name,namespace,deletionGracePeriodSeconds。

pod.spec

bash 复制代码
[root@master30 ~]# kubectl explain pod.spec | grep '^  [a-zA-Z]'
   activeDeadlineSeconds	<integer>
   affinity	<Object>
   automountServiceAccountToken	<boolean>
   containers	<[]Object> -required-
   dnsConfig	<Object>
   dnsPolicy	<string>
   enableServiceLinks	<boolean>
   ephemeralContainers	<[]Object>
   hostAliases	<[]Object>
   hostIPC	<boolean>
   hostNetwork	<boolean>
   hostPID	<boolean>
   hostname	<string>
   imagePullSecrets	<[]Object>
   initContainers	<[]Object>
   nodeName	<string>
   nodeSelector	<map[string]string>
   overhead	<map[string]string>
   preemptionPolicy	<string>
   priority	<integer>
   priorityClassName	<string>
   readinessGates	<[]Object>
   restartPolicy	<string>
   runtimeClassName	<string>
   schedulerName	<string>
   securityContext	<Object>
   serviceAccount	<string>
   serviceAccountName	<string>
   setHostnameAsFQDN	<boolean>
   shareProcessNamespace	<boolean>
   subdomain	<string>
   terminationGracePeriodSeconds	<integer>
   tolerations	<[]Object>
   topologySpreadConstraints	<[]Object>
   volumes	<[]Object>

重点关注:containers、nodeName、volumes等。

pod.spec.containers
bash 复制代码
[root@master30 ~]# kubectl explain pod.spec.containers | grep '^   [a-zA-Z]'
   args	<[]string>
   command	<[]string>
   env	<[]Object>
   envFrom	<[]Object>
   image	<string>
   imagePullPolicy	<string>
   lifecycle	<Object>
   livenessProbe	<Object>
   name	<string> -required-
   ports	<[]Object>
   readinessProbe	<Object>
   resources	<Object>
   securityContext	<Object>
   startupProbe	<Object>
   stdin	<boolean>
   stdinOnce	<boolean>
   terminationMessagePath	<string>
   terminationMessagePolicy	<string>
   tty	<boolean>
   volumeDevices	<[]Object>
   volumeMounts	<[]Object>
   workingDir	<string>

重点关注:command、env、image、imagePullPolicy、volumeMounts等。

pod.spec.containers.ImagePullPolicy
  • Always,总是从仓库下载镜像。
  • Never,只使用本地镜像,不下载。
  • IfNotPresent,优先使用本地镜像,如果没有才从仓库下载镜像。
pod lifecycle 和 status
pod lifecycle
  • pod的生命周期取决于pod中所有容器的生命周期。
  • 容器的生命周期取决于容器中进程的生命周期。
Pod status

常见 pod 状态如下:

  • ContainerCreating 正在创建
  • Running 正在运行
  • Completed 运行完成
  • Error/RunContainerError 运行错误
  • CrashLoopBackOff 重新创建
  • ErrImagePull 获取镜像错误
  • ImagePullBackOff 重新获取镜像
  • Terminating,正在终止(删除)

实验1:pod中包含1个容器,验证pod状态

监控命令: watch -n 1 kubectl get pod

示例1:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']

command命令可以改写如下:

yaml 复制代码
command:
- sh
- -c
- echo OK! && sleep 10

或者

yaml 复制代码
args:
- sh
- -c
- echo OK! && sleep 10

观察pod状态为:ContainerCreating-->Running-->Completed

示例2:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

观察pod状态为:ContainerCreating-->Error

实验2:pod中包含2个容器,验证pod状态

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']

观察pod状态为:ContainerCreating-->Running-->NotReady(其中一个先完成)-->Completed(两个都完成)

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echoxx Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 20']

观察pod状态为:ContainerCreating-->Error

pod.spec.restartPolicy

示例:

yaml 复制代码
  restartPolicy: Never
  containers:
  - name: myapp-container
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 5'] 

restartPolicy,针对pod中所有容器生效。

  • Always,除了 Running 状态,其他状态总是重启,默认值。
  • OnFailure,失败了才重启。
  • Never,从不重启。

实验1:验证pod中含有单个容器重启策略。

更改pod重启策略,直接apply会报错,需要删除重建。

第一个yaml验证Always/OnFailure/Never重启策略

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Always/OnFailure/Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']

第二个yaml验证OnFailure

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: OnFailure
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

第三个yaml验证 Never 重启策略

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

实验2:验证pod中含有多个容器重启策略。

验证结果:只要有一个容器满足重启策略条件,就会重启。

示例1:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Always/OnFailure/Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']

使用Always重启策略时,当容器busybox1状态为Completed时,容器busybox2还未创建成功,此时会根据重启策略重启pod。当然也可以将容器的生命周期延长,sleep 5改为sleep 50,运行50s之后还会重启pod。

使用OnFailure/Never重启策略就不会出现这种情况。

示例2:第二个command是错误的。

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Always/OnFailure/Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

Always和OnFailure重启策略总是会重启pod;Never重启策略就不会重启pod。

Init Containers

一个pod可以有多个容器在其中运行应用程序,也可以有一个或多个initContainers。initContainers中容器状态必须是complete,containers容器才能运行。

如果pod的initContainers fail,kubernetes根据restartpolicy重启pod,直到initContainers状态为complete。

如果pod中initContainers有多个容器,那么会按顺序创建和执行。按顺序执行的initContainers必须成功才能执行下一个initContainers。所有init全部成功执行完成后,才开始执行pod中常规容器。

使用场景:

1、等待某个服务创建成功。

复制代码
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1

2、等待固定时间后再运行app容器。

复制代码
sleep 60

3、Clone a git repository into a volume

示例1:

bash 复制代码
root@master30:~/pods# vim pod-myapp.yaml
yaml 复制代码
# myservice
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

# mydb
---
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377

# myapp
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  initContainers:
  - name: init-myservice
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;sleep 3;']
  - name: init-mydb
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;sleep 3;']
  containers:
  - name: myapp-container
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']

首先创建2个service,然后创建pod,观察pod状态变化。

示例2:

bash 复制代码
root@master30:~/pods# vim pod-myapp.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  volumes:
  - name: workdir
    emptyDir: {}
  containers:
  - name: myapp-container
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  initContainers:
  - name: init-poda
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'touch /work-dir/aa.txt && sleep 10']
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"

在app容器中查看文件

bash 复制代码
[root@master30 ~]# kubectl exec myapp-pod -c myapp-container -- ls /xx

pod的状态变化:Init:0/1->PodInitializing->Running

将初始化容器command变更为以下内容再测试:

复制代码
command: ['sh', '-c', 'touchxx /work-dir/aa.txt']

pod的状态变化:

Init:0/1->Init:Error->Init:CrashLoopBackOff,然后Init:Error->Init:CrashLoopBackOff循环。

静态 pod

**问题:**正常情况下,pod 由 master 节点统一管理。那么 master 上的kube-apiserver、kube-scheduler、kube-controller-manager等pod又是由谁来管理的呢?

答案kubelet 服务。master节点上组件以静态Pod方式运行,由本地kubelet进行管理。它们不能通过API Server进行管理,无法与ReplicationController、Deployment或DaemonSet进行关联,并且kubelet也无法对其健康检查。

我们来分析下 kubelet.service 配置。

bash 复制代码
[root@master30 ~]# systemctl status kubelet.service |cat
● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: active (running) since Sun 2024-07-14 09:52:08 UTC; 1h 7min ago
       Docs: https://kubernetes.io/docs/
   Main PID: 7489 (kubelet)
      Tasks: 11 (limit: 4557)
     Memory: 39.0M (peak: 39.9M)
        CPU: 1min 45.913s
     CGroup: /system.slice/kubelet.service
             └─7489 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.9
......

[root@master30 ~]# cat /usr/lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target

# kubelet.service服务启动参数通过 Drop-In 文件 10-kubeadm.conf 配置
[root@master30 ~]# cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf 
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS

# 以下参数定义了kubelet配置文件位置
# KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml
# 该文件中的 staticPodPath 参数定义了一个目录
# kubelet会定期扫描该目录中pod文件,并根据目标中文件变动创建和删除pod
[root@master30 ~]# grep staticPodPath /var/lib/kubelet/config.yaml
staticPodPath: /etc/kubernetes/manifests

[root@master30 ~]# ls -1 /etc/kubernetes/manifests
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml

**注意:**不要修改 staticPodPath 参数配置,否则需要将集群组件4个yaml文件也要复制过去。

我们还可以通过参数 --pod-manifest-path设置,该目录下所有 pod 也是静态 pod。

bash 复制代码
[root@master30 ~]# kubelet --help|grep pod-manifest-path
      --pod-manifest-path string    Path to the directory containing static pod files to run, or the path to a single static pod file. Files starting with dots will be ignored. (DEPRECATED: This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)

思考

1. kubernetes 中 pod 和 container 区别?

答:

容器是运行时概念真正跑应用的进程环境

kubernetes 中 Pod:是 K8s 独有的概念 ,是 K8s 中最小调度、管理、自愈单元,是容器的"外壳 + 运行环境"

  • **一个 Pod 里可以有 1 个或多个容器,**pod中所有容器:
    • 同住一个房间 ,共用网络、存储
    • 一起被调度到同一台机器,一起销毁。
特性 容器 Pod
K8s 最小调度单位 ❌ 不是 ✅ 是
独立 IP ✅ 有 ✅ 有
独立 存储 ✅ 有 ✅ 有
多容器支持 ❌ 不支持 ✅ 天然支持
网络/存储共享 ❌ 不能 ✅ 内部容器可共享
生命周期管理 ❌ 弱 ✅ 完整(重启、自愈)
属于谁 运行时(Docker/containerd) Kubernetes

2. kubernetes 为什么直接管理 pod 而不是容器?

  1. 容器太"原子",不适合直接调度。K8s 需要一个能直接被调度、能独立运行、有完整身份 的对象--Pod
  • 容器:只是一个进程/运行环境(Docker/containerd)。

  • Pod:是容器的封装 + 网络/存储/配置/生命周期的统一抽象 。K8s 调度、扩缩容、自愈、服务发现、监控......全都以 Pod 为单位

  1. Pod 支持"多容器协同"(最关键设计)。

    很多场景必须多个容器一起跑、共享资源

    • 业务容器 + Sidecar(日志、监控、代理)
    • 业务容器 + InitContainer(初始化)
    • 业务容器 + 网络/安全代理容器

    它们需要:

    • 共享 Network Namespace(同一个 IP、端口空间)
    • 共享 Volume
    • 一起调度到同一台机器
  2. Pod 提供统一的生命周期与自愈

    K8s 要做:

    • 重启失败容器
    • 替换崩溃节点上的实例
    • 滚动更新、回滚
    • 扩缩容

    这些行为必须作用在一个稳定、标准、独立的单元上:

    • 如果直接管容器,多容器应用会乱
    • 以 Pod 为单位,管理语义清晰、一致
  3. 解耦底层容器运行时。

    Pod 屏蔽了底层实现:

    • Docker
    • containerd
    • cri-o
    • 其他 CRI 运行时

    K8s 只跟 Pod/CRI 打交道,不绑定某一种容器技术。

3. 解释 pod 中 pause 容器作用

在 Kubernetes 里,每个 Pod 都会自动创建一个 pause 容器(也叫 infra 容器) ,它是 Pod 里第一个启动、最后退出的容器,作用非常关键。

  1. pause 容器是干嘛的?

    pause 容器就是为了"占坑",把 Pod 的网络和命名空间先 hold 住。

  2. 它的 3 个核心作用

    创建并持有 Pod 的 Linux Namespace

    Pod 里所有容器要共享:

    • Network namespace(同一个 IP、端口)
    • PID namespace(可选)
    • IPC namespace

    这些共享空间必须由一个"永远不死"的容器来持有 ,否则共享空间会消失。这个容器就是 pause

    让 Pod 生命周期独立于业务容器

    • 业务容器挂了 → 重启
    • pause 容器不挂 → Pod 就不会消失
    • 网络、IP、存储挂载都能保持不变

    如果没有 pause:业务容器一退出,整个 Pod 的网络就没了,重启也没用。

    实现多容器共享网络

    nginx、业务容器、sidecar 都加入 pause 的 network namespace:

    • 共享同一个 IP
    • 可以用 127.0.0.1 互相访问
    • 端口不能冲突
  3. 超形象比喻

    • pause = 房东
    • Pod = 房子
    • 业务容器 = 租客

    房东(pause)先占好房子(网络/命名空间),租客(业务容器)才能住进来。租客换了一波又一波,房子一直都在。

  4. 一个 Pod 内部结构(最标准)

    bash 复制代码
    Pod
    ├── pause 容器(infra)------ 永远第一个启动
    │    持有:网络命名空间、IP、IPC
    └── 业务容器 1、2、3...
         都加入 pause 的命名空间
  5. 最精炼总结

    pause 容器 = Pod 的基石

    • 只负责 holding namespace
    • 保证 Pod 网络、IP、生命周期稳定

环境清理

bash 复制代码
[root@master30 ~]# kubectl delete ns pods

编写 kubernetes 资源文件

python 安装

为后续 python 开发做准备。

  1. 下载安装包 :打开浏览器,访问Python 官方网站 → 点击顶部 Downloads → 选择 Windows → 在 Stable Releases(稳定版)区域,点击 Python 3.14.x(x 为最新小版本)对应的 Download 按钮 → 选择 Windows installer (64-bit)(64 位系统,主流电脑均支持)。
  2. 运行安装包 :找到下载好的python-3.14.x-amd64.exe文件,双击运行 → 关键步骤 :勾选窗口底部的 Add Python 3.14 to PATH(这一步是让系统能在任意位置调用 Python,必须勾选!) → 点击 Install Now(默认安装,也可选择 Customize installation 自定义路径)。
  3. 验证安装结果 :按下Win + R,输入cmd打开命令提示符 → 输入python --version(注意是两个短横线),如果输出Python 3.14.x,说明安装成功;如果提示 python 不是内部或外部命令,则是 Add to PATH 未勾选,需重新安装并勾选该选项。

pycharm 安装和配置

1 PyCharm 安装

PyCharm 版本:

  • 社区版(Community):免费开源,支持 Python 核心开发功能,适合新手;

  • 专业版(Professional):付费,支持 Web 开发、数据库等高级功能,适合企业开发。

安装步骤

实验环境安装 2025.3 版本。

  1. 访问JetBrains 官网 → 点击 Download → 选择 Community 版本 → 下载对应系统的安装包;

    历史版本:https://www.jetbrains.com/pycharm/download/other.html

  2. 运行安装包:勾选 Create Desktop Shortcut(创建桌面快捷方式)、Add launchers dir to PATH(可选)→ 点击 Next→ 选择安装路径→ 点击 Install

2 PyCharm 激活

  1. 找老师获取激活插件jetbra.zip,解压后查看 scripts 文件夹中文件清单。

    提示:激活工具存放的路径不能包含中文字符。

  1. 先执行uninstall-all-users.vbs,直接双击打开,此步骤是为了防止之前有过激活信息,确保当前环境变量下没有激活工具的变量信息,可先执行卸载脚本,再进行后面的激活操作,避免激活失败。

    出现弹框done说明成功。

  2. 然后再执行install-current-user.vbs,直接双击打开即可。

    这里需要等待10秒左右才会出现done弹框,才是成功。

  3. 重新打开PyCharm应用,点击菜单栏:Help->Manage Subscriptions...

    点击 Activate Another Subscription...

    输入激活码!

    激活效果如下:

激活码

ini 复制代码
X9MQ8ML8U7-eyJsaWNlbnNlSWQiOiJYOU1ROE1MOFU3IiwibGljZW5zZWVOYW1lIjoiY29tbXVuaXR5LXN1cHBvcnRAamV0YnJhaW5zLmNvbSIsImFzc2lnbmVlTmFtZSI6Imh0dHBzOi8vZ2l0aHViLmZscy5qZXRicmFpbnMuY29tIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IiIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiSUkiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJBQyIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRQTiIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlBTIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiR08iLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJETSIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkNMIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlMwIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiRFMiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSQyIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJEIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUEMiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU1UiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSTSIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IldTIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiREIiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEQyIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRQIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQREIiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJSU0MiLCJmYWxsYmFja0RhdGUiOiIyMDk5LTEyLTMxIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTRiIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFNJIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQQ1dNUCIsImZhbGxiYWNrRGF0ZSI6IjIwOTktMTItMzEiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlNWIiwiZmFsbGJhY2tEYXRlIjoiMjA5OS0xMi0zMSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfV0sIm1ldGFkYXRhIjoiMDEyMDIzMTIwOUxQQUEwMDEwMDkiLCJoYXNoIjoiVFJJQUw6MjAxNi4xIiwiZ3JhY2VQZXJpb2REYXlzIjozLCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-dtBVL2U2dlUXxVVl2pg1ZwpX3dqXYBlft78bRigYCPkmucXinFZsdSP6q30dZWgBixK5QRK449wa4EDACPaY6i2tq/Jfn7yq8KMwDe/nTulNScSvtt7Qn94fDsKOLO0icPcBW9LzqVvVMD/qX4USIOFFtTA+zsabCE0fZVr7XaS4vFiT32dbBIEaZFOSjm44fCwmyH7+1YhQozCvAUaTR8bRP4hMos3LkJNpEBxHmiHUEaWFZEHemFGu/Tr7/KjqivaXHuxFG1SKFa0cJQvcNbo/r1unvMdg2PxyEzKpItH6Pt3jWLh8ZPRoTtMWEDa66O1JHZ9Iprn/KUHErTR+pw==-MIIETzCCAjegAwIBAgIEU7kY4jANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIyMTAxMDE2MDU0NFoXDTI0MTAxMTE2MDU0NFowHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMjEwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0QBxb4pfhYqM/RjSsvizyIncjO1EwCRgxPbKCcRFSY3ANBzS3hUdBzIxNuVbEPlnw50ItAn1iUwlyQ3QC7T+aG9E2R3IIIfEppb4F2SBi3YtgcZc3IrLgz8wa2p0iWTkkbFwnJxD4jMBfw9HDDbS5r9d9HVcPDH0rA+4nNIm7yek0wU6D77KJUWcNm7QHJfLeJAoOno+G3UIsnu7f63XRGkvdxK7L/WFzD9hCfSwZqmPZkCcrDLJTBdU4UpoJrfIoSeXZ+ssrSdQ9qY0JfUmRWvJNuUKeDBv6TI3ZCipJeZzXXafE7xD3Q57YS6KlIJEUzjZ2CRJIK3Zu5aqUTHbAgMBAAGjgZkwgZYwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDAdBgNVHQ4EFgQUQ0INJl2tuM1XlTAfueTuWydc7qIwDQYJKoZIhvcNAQELBQADggIBACzJFycVHjlSCEczoAHxgtF7NG4sDcpgmLh6nrMIZpDLLGc/whCv6vpcDkBo0XvuQwmZnbpf/Ndpy4ypP2OXIw94TlfOkGKVLdHDQU8ES1HpgAtscFtNg4dyZijF4pLgiK2nbCokvHI3oWQZY3ROswrjsh0HNHWdVKooEhWt3vBpXorusNRNWbwidznxySM5aABbHrlW0+EgXuLMEHBrybLu0QenEuTFZS3E91uSa7JLpU92aQyAmZUJAhogfIvssgwnmyfnOF3csixUV6lDBCf+SUGzQbYtZd/QsGI9uUUhBbLjoZnFhVEbbOntmB4/aUvSziZnbhRAY+OhVTrNX6GtXI03cAxVBk2Kh6DE62vBW3biBGHK5ClsQGW1f5RLWhqJh0d3EP6+dsAo2P3Ic5MCuspFwSfWoK3gNhvYlr57PNrzAWhBn6Od78RMaqg+dl+GHsm5sW5mbvXpvYNukEe1RHVIONl8OTKex1U12DeS4pAIA9aQxd1vYapmNdam3rnOQbynKLYa09aDPrWO5Y+LtaCix7TBmwXPtyCxBLK4S7EZ+FE7Xz322ulpKcvLZCTKBzUH5y62xHIcSijnxJfSU0W5UCApsnwochM5S6RPuVpvyQoBR5IX3Ugjw48jpuf2TGL/INWPHQ5AjK9ZNtWAfpkYc9w+AcNAa/v6J/Ha

3 设置中文语言

  1. 打开设置界面:菜单栏 File->Settings或者Ctrl+Alt+s。

  2. 安装中文插件:依次点击Plugins->Marketplace->搜索chinese->找到中文简体语言包,然后点击Install安装。

    安装完成后,重启 pycharm。

  3. 中文界面如下:

  4. 如果重启还是英文,则需要手动设置语言。

    1. 再次打开设置:菜单栏 File->Settings...或者Ctrl+Alt+s。

    2. 进入:Appearance & Behavior → System Settings →Language and Region ,选择:简体中文

    3. 重启 PyCharm 即可。

4 PyCharm 配置项目与环境

  1. 创建新项目 :打开 PyCharm → 在欢迎界面点击 新建项目 ,也可以通过菜单 文件->新建项目

    配置以下选项:

    • 位置:选择项目保存路径(不要包含中文 / 空格)。
    • 不勾选创建欢迎脚本(可选)。
    • 解释器类型:选择项目 venv。

    开始创建项目文件:右下角可以看到具体执行任务。

  2. 验证环境配置:在 PyCharm 的右下角,会显示当前项目使用的 Python 环境(比如Python 3.14),说明配置成功。

kubernetes 插件安装

  1. 打开 PyCharm,依次点击菜单:文件设置插件

  2. 切换到 Marketplace 标签,搜索 Kubernetes (JetBrains 官方出品),点击 安装,安装完成后重启 IDE 生效。

如果这里安装失败,提示如下:

我们可以从官网下载插件,并导入。

选择匹配自己的版本。

在插件安装界面,点击齿轮图标,选择从磁盘安装插件

选择对应文件

安装成功后,在已安装标签下可以看到对应的插件。

创建 Kubernetes 资源文件

右键点击项目->新建->Kubernetes 资源

以pod为例,输入完成回车即可。

效果如下:

清空模板文件内容,编写首行 apiVersion,发现不能补全,但是 apiVersion 编写完成后,后续补全就正常了。

建议额外设置文件类型:右键webapp.yaml文件->重写文件类型->Kubernetes Yaml。

此时删除文件内容,手动编写内容,自动补全效果如下:

Python 3.14),说明配置成功。

外链图片转存中...(img-PSHroYZR-1783386251960)

kubernetes 插件安装

  1. 打开 PyCharm,依次点击菜单:文件设置插件

  2. 切换到 Marketplace 标签,搜索 Kubernetes (JetBrains 官方出品),点击 安装,安装完成后重启 IDE 生效。

    外链图片转存中...(img-gKBaNAqQ-1783386251960)

如果这里安装失败,提示如下:

外链图片转存中...(img-2ubmmZkh-1783386251961)

我们可以从官网下载插件,并导入。

外链图片转存中...(img-WhKZa9Xi-1783386251961)

选择匹配自己的版本。

外链图片转存中...(img-8r5tUhd0-1783386251961)

在插件安装界面,点击齿轮图标,选择从磁盘安装插件

外链图片转存中...(img-tuJoXMjm-1783386251961)

选择对应文件

外链图片转存中...(img-IP6mkNCI-1783386251962)

安装成功后,在已安装标签下可以看到对应的插件。

外链图片转存中...(img-bHjjyRUU-1783386251962)

创建 Kubernetes 资源文件

右键点击项目->新建->Kubernetes 资源

外链图片转存中...(img-gNhUVpkO-1783386251962)

以pod为例,输入完成回车即可。

外链图片转存中...(img-TwOgCUwN-1783386251962)

效果如下:

外链图片转存中...(img-edOredU6-1783386251962)

清空模板文件内容,编写首行 apiVersion,发现不能补全,但是 apiVersion 编写完成后,后续补全就正常了。

建议额外设置文件类型:右键webapp.yaml文件->重写文件类型->Kubernetes Yaml。

外链图片转存中...(img-Ts98a29m-1783386251963)\] \[外链图片转存中...(img-YH1oDerz-1783386251963)

此时删除文件内容,手动编写内容,自动补全效果如下:

外链图片转存中...(img-KPnzSLIJ-1783386251963)

外链图片转存中...(img-hSv0cAIc-1783386251963)

外链图片转存中...(img-423xKqYM-1783386251968)

相关推荐
爱好曙光3 小时前
云原生混沌工程实战:基于Litmus的故障注入与弹性测试
云原生·kubernetes·devops·混沌工程·故障注入·litmus·弹性测试
HAPPY酷3 小时前
【ROS2】VMware + Docker 运行 Gazebo 崩溃与“假死”排查实录
qt·docker·容器
探索云原生4 小时前
Kueue 如何管理 DRA 模式下的 GPU 配额
ai·云原生·kubernetes·kueue
Aray12346 小时前
论服务网格在云原生微服务项目中的设计与落地实践
微服务·云原生·架构
Zhao_yani6 小时前
k8s基础知识
云原生·容器·kubernetes
styshoo6 小时前
NVSentinel 数据流梳理
kubernetes·gpu·ai-infra·nvsentinel
运维大师7 小时前
【云原生与DevOps】07-Istio服务网格落地:从试点到全量的踩坑记录
云原生·istio·devops
想你依然心痛7 小时前
嵌入式容器:Docker与BalenaOS在边缘设备上的实践——容器运行时与OTA
运维·docker·容器
zx78547 小时前
Kubernetes 生产级实战:从零部署 LNMP 架构 ECShop 商城(完整指南)
容器·架构·kubernetes