简介
本教程将指导你在 Kubernetes 容器(pod)启动时运行命令。你将学习如何使用 command
和 args
字段配置启动命令、执行多个命令以及处理启动失败的情况。我们将使用 Minikube 创建一个本地 Kubernetes 环境,让你可以亲身体验这些概念。
在本实验结束时,你将了解如何在启动期间自定义 Kubernetes 容器的行为,并确保应用程序顺利部署。这些知识对于在 Kubernetes 环境中正确配置容器化应用程序至关重要。
本教程将指导你在 Kubernetes 容器(pod)启动时运行命令。你将学习如何使用 command
和 args
字段配置启动命令、执行多个命令以及处理启动失败的情况。我们将使用 Minikube 创建一个本地 Kubernetes 环境,让你可以亲身体验这些概念。
在本实验结束时,你将了解如何在启动期间自定义 Kubernetes 容器的行为,并确保应用程序顺利部署。这些知识对于在 Kubernetes 环境中正确配置容器化应用程序至关重要。
在这一步,我们将通过启动 Minikube 并了解本实验所需的基本 Kubernetes 概念来准备我们的环境。
Kubernetes 是一个开源平台,旨在自动化应用程序容器的部署、扩展和运维。Kubernetes 的核心是容器(Pod)——可以创建和管理的最小可部署单元。
Minikube 是一个让你在本地运行 Kubernetes 的工具。让我们启动它:
minikube start --driver=docker
此命令将使用 Docker 作为驱动程序创建一个本地 Kubernetes 集群。启动过程可能需要几分钟,因为它会下载必要的组件。
你应该会看到类似以下的输出:
😄 minikube v1.30.1 on Ubuntu 22.04
✨ Using the docker driver based on user configuration
📌 Using Docker driver with root privileges
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🔥 Creating docker container (CPUs=2, Memory=2200MB) ...
🐳 Preparing Kubernetes v1.27.4 on Docker 24.0.4 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎 Verifying Kubernetes components...
🌟 Enabled addons: default-storageclass, storage-provisioner
💡 kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
让我们通过检查 Minikube 集群的状态来验证一切是否正常工作:
minikube status
你应该会看到表明 Minikube 正在运行的输出:
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
现在让我们检查 kubectl
(Kubernetes 命令行工具)是否已正确配置:
kubectl get nodes
你应该会看到一个节点(你的 Minikube 实例)显示为 Ready:
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 2m15s v1.27.4
容器(Pod)是 Kubernetes 应用程序的基本执行单元。每个容器代表集群上的一个运行进程,并封装了一个或多个容器。容器在设计上是短暂的,这意味着它们可以根据需要创建、销毁和重新创建。
在 Kubernetes 中,你通常在 YAML 文件中定义容器。对于本实验,我们已经在你的环境中准备了一些示例 YAML 文件。
让我们进入这些文件所在的目录:
cd ~/project/kubernetes-examples
ls -la
你应该会看到以下文件:
total 20
drwxr-xr-x 2 labex labex 4096 Sep 21 10:00 .
drwxr-xr-x 3 labex labex 4096 Sep 21 10:00 ..
-rw-r--r-- 1 labex labex 193 Sep 21 10:00 basic-pod.yaml
-rw-r--r-- 1 labex labex 254 Sep 21 10:00 liveness-probe-pod.yaml
-rw-r--r-- 1 labex labex 312 Sep 21 10:00 multi-command-pod.yaml
-rw-r--r-- 1 labex labex 263 Sep 21 10:00 startup-command-pod.yaml
现在我们的环境已经设置好,我们准备好开始使用 Kubernetes 容器并学习如何在启动时运行命令了。
在这一步,我们将创建第一个 Kubernetes 容器(Pod),并了解它如何在启动时执行命令。我们将研究 command
字段,该字段定义了容器启动时应运行的内容。
首先,让我们查看一个基本容器的配置。使用 nano
编辑器打开 basic-pod.yaml
文件:
nano basic-pod.yaml
你会看到一个包含以下内容的 YAML 文件:
apiVersion: v1
kind: Pod
metadata:
name: basic-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/bash", "-c", "echo 'Pod is running' && sleep 3600"]
此配置定义了:
basic-pod
的容器(Pod)ubuntu
的单个容器,使用 ubuntu:20.04
镜像command
字段指定了容器启动时将运行的可执行文件。在这种情况下,我们使用 -c
标志运行 /bin/bash
shell,这允许我们传递一串要执行的命令。
按 Ctrl+X
退出 nano
编辑器。
让我们在 Kubernetes 集群中创建这个容器:
kubectl apply -f basic-pod.yaml
你应该会看到类似以下的输出:
pod/basic-pod created
现在,让我们检查容器是否正常运行:
kubectl get pods
你应该会看到类似以下的输出:
NAME READY STATUS RESTARTS AGE
basic-pod 1/1 Running 0 30s
这表明我们的容器正在成功运行。READY
列下的 1/1
表示在预期的一个容器中,有一个容器正在运行。
要查看启动命令的输出,我们可以检查容器的日志:
kubectl logs basic-pod
你应该会看到:
Pod is running
这证实了我们的启动命令已成功执行。
让我们通过执行交互式 shell 来查看容器内部正在发生的事情:
kubectl exec -it basic-pod -- /bin/bash
现在你已进入容器的 shell。让我们验证我们的进程是否正在运行:
ps aux
你应该会看到休眠命令正在运行,它是我们启动命令的一部分:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4112 3372 ? Ss 10:05 0:00 /bin/bash -c echo 'Pod is running' && sleep 3600
root 7 0.0 0.0 4112 3536 pts/0 Ss 10:06 0:00 /bin/bash
root 14 0.0 0.0 5900 2928 pts/0 R+ 10:06 0:00 ps aux
root 15 0.0 0.0 2512 580 ? S 10:06 0:00 sleep 3600
PID 为 1 的进程是我们的启动命令,sleep 3600
命令作为一个单独的进程正在运行。
通过输入以下命令退出容器 shell:
exit
当你创建一个容器时,它会经历几个阶段:
我们的容器处于 Running
状态,因为我们的主进程(sleep 3600
)仍在运行。当此进程完成或被终止时,容器将根据退出代码转换为 Succeeded
或 Failed
状态。
现在你已经了解了如何创建一个基本容器,并使用 command
字段在启动时运行命令。
在这一步,你将学习如何结合使用 command
和 args
字段,在 Kubernetes 容器(Pod)中配置更复杂的启动行为。
Kubernetes 提供了两种主要方式来指定容器启动时运行的命令:
command
:指定要运行的可执行文件(类似于 Docker 的 ENTRYPOINT
)args
:指定传递给命令的参数(类似于 Docker 的 CMD
)单独或结合使用这些字段,能让你灵活地控制容器的启动方式。
让我们查看 startup-command-pod.yaml
文件:
nano startup-command-pod.yaml
你会看到以下配置:
apiVersion: v1
kind: Pod
metadata:
name: startup-command-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/bash"]
args:
["-c", "echo 'Custom startup message' > /tmp/startup.txt && sleep 3600"]
在此配置中:
command
字段指定要运行 /bin/bash
args
字段提供传递给 bash
的参数:-c
和包含命令的字符串这种将命令和参数分开的方式,使配置更易读、更易维护。
按 Ctrl+X
退出 nano
编辑器。
让我们创建这个容器:
kubectl apply -f startup-command-pod.yaml
你应该会看到:
pod/startup-command-pod created
验证容器是否正在运行:
kubectl get pods startup-command-pod
你应该会看到:
NAME READY STATUS RESTARTS AGE
startup-command-pod 1/1 Running 0 30s
现在,让我们通过检查是否创建了预期的文件,来验证启动命令是否正确执行:
kubectl exec startup-command-pod -- cat /tmp/startup.txt
你应该会看到:
Custom startup message
这证实了命令已成功执行,并创建了包含指定内容的文件。
理解 command
和 args
之间的关系很重要:
command
,它将覆盖容器镜像的默认 ENTRYPOINT
args
,它将覆盖容器镜像的默认 CMD
command
和 args
,它们将同时覆盖 ENTRYPOINT
和 CMD
让我们看看修改容器配置会发生什么。创建一个名为 modified-command-pod.yaml
的新文件:
nano modified-command-pod.yaml
添加以下内容:
apiVersion: v1
kind: Pod
metadata:
name: modified-command-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/echo"]
args: ["This message is printed by echo"]
按 Ctrl+X
,然后按 Y
和 Enter
保存并退出。
现在,让我们创建这个容器:
kubectl apply -f modified-command-pod.yaml
你应该会看到:
pod/modified-command-pod created
查看日志,了解发生了什么:
kubectl logs modified-command-pod
你应该会看到:
This message is printed by echo
注意容器如何使用指定的参数执行 /bin/echo
命令,然后在 echo
打印输出后终止。
检查容器状态:
kubectl get pods modified-command-pod
你应该会看到类似以下内容:
NAME READY STATUS RESTARTS AGE
modified-command-pod 0/1 Completed 0 45s
Completed
状态表示容器已运行完成并成功退出。
现在你已经了解了如何结合使用 command
和 args
来配置 Kubernetes 容器的启动行为。
在这一步,你将学习如何在容器(Pod)启动时执行多条命令,以及如何使用健康检查来处理启动失败的情况。
通常,你需要在容器启动时运行多条命令。在 Kubernetes 中有几种方法可以实现这一点:
&&
、;
等)来链接命令让我们通过查看 multi-command-pod.yaml
文件来探索第一种方法:
nano multi-command-pod.yaml
你会看到:
apiVersion: v1
kind: Pod
metadata:
name: multi-command-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/bash", "-c"]
args:
[
"echo 'First command' > /tmp/first.txt && echo 'Second command' > /tmp/second.txt && sleep 3600"
]
此配置使用 &&
操作符将多条命令链接在一起,只有当前一条命令成功执行时,才会执行下一条命令。
按 Ctrl+X
退出编辑器。
让我们创建这个容器:
kubectl apply -f multi-command-pod.yaml
你应该会看到:
pod/multi-command-pod created
现在,让我们通过检查创建的文件来验证两条命令是否都已执行:
kubectl exec multi-command-pod -- cat /tmp/first.txt
你应该会看到:
First command
对于第二个文件:
kubectl exec multi-command-pod -- cat /tmp/second.txt
你应该会看到:
Second command
Kubernetes 提供了检测和处理启动失败的机制:
让我们查看一个使用存活探针的容器:
nano liveness-probe-pod.yaml
你会看到:
apiVersion: v1
kind: Pod
metadata:
name: liveness-probe-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/bash", "-c"]
args: ["touch /tmp/healthy && sleep 3600"]
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]
initialDelaySeconds: 5
periodSeconds: 5
在此配置中:
/tmp/healthy
按 Ctrl+X
退出编辑器。
让我们创建这个容器:
kubectl apply -f liveness-probe-pod.yaml
你应该会看到:
pod/liveness-probe-pod created
检查容器是否正在运行:
kubectl get pods liveness-probe-pod
你应该会看到:
NAME READY STATUS RESTARTS AGE
liveness-probe-pod 1/1 Running 0 30s
现在,让我们看看如果删除健康检查文件会发生什么:
kubectl exec liveness-probe-pod -- rm /tmp/healthy
等待约 10 秒,然后再次检查容器状态:
kubectl get pods liveness-probe-pod
你应该会看到容器已被重启:
NAME READY STATUS RESTARTS AGE
liveness-probe-pod 1/1 Running 1 60s
RESTARTS
计数已增加到 1,表明 Kubernetes 检测到容器处于不健康状态并重启了它。
让我们验证健康检查文件是否再次存在(容器重启时,启动命令应该会重新创建该文件):
kubectl exec liveness-probe-pod -- ls -la /tmp/healthy
你应该会看到文件再次存在:
-rw-r--r-- 1 root root 0 Sep 21 10:30 /tmp/healthy
这展示了 Kubernetes 如何自动从启动失败中恢复,并维持应用程序的期望状态。
对于更复杂的初始化操作,你可能需要使用自定义启动脚本。让我们创建一个使用 shell 脚本进行启动的容器:
nano script-pod.yaml
添加以下内容:
apiVersion: v1
kind: Pod
metadata:
name: script-pod
spec:
containers:
- name: ubuntu
image: ubuntu:20.04
command: ["/bin/bash", "-c"]
args:
- |
cat > /tmp/startup.sh << 'EOF'
#!/bin/bash
echo "Script started at $(date)" > /tmp/script-log.txt
echo "Creating configuration files..." >> /tmp/script-log.txt
mkdir -p /tmp/config
echo "app_name=MyApp" > /tmp/config/app.conf
echo "version=1.0" >> /tmp/config/app.conf
echo "Script completed successfully" >> /tmp/script-log.txt
EOF
chmod +x /tmp/startup.sh
/tmp/startup.sh
sleep 3600
此配置:
sleep
命令保持容器运行按 Ctrl+X
,然后按 Y
和 Enter
保存并退出。
让我们创建这个容器:
kubectl apply -f script-pod.yaml
你应该会看到:
pod/script-pod created
等待片刻,让容器启动,然后检查其状态:
kubectl get pods script-pod
你应该会看到:
NAME READY STATUS RESTARTS AGE
script-pod 1/1 Running 0 30s
现在,让我们检查脚本的输出:
kubectl exec script-pod -- cat /tmp/script-log.txt
你应该会看到类似以下内容:
Script started at Tue Sep 21 10:35:42 UTC 2023
Creating configuration files...
Script completed successfully
让我们验证配置文件是否已创建:
kubectl exec script-pod -- cat /tmp/config/app.conf
你应该会看到:
app_name=MyApp
version=1.0
这展示了如何使用复杂的启动脚本来初始化 Kubernetes 中的容器。
在最后这一步,你将探索在 Kubernetes 容器(Pod)启动时运行命令的最佳实践,并创建一个实现这些实践的实际应用示例。
在为 Kubernetes 容器配置启动命令时,请考虑以下最佳实践:
初始化容器在应用容器启动之前运行,非常适合用于设置任务。让我们创建一个带有初始化容器的容器:
nano init-container-pod.yaml
添加以下内容:
apiVersion: v1
kind: Pod
metadata:
name: init-container-pod
spec:
initContainers:
- name: init-config
image: ubuntu:20.04
command: ["/bin/bash", "-c"]
args:
- |
echo "Initializing configuration..."
mkdir -p /work-dir/config
echo "database_url=mysql://user:password@db:3306/mydb" > /work-dir/config/db.conf
echo "api_key=1234567890" > /work-dir/config/api.conf
echo "Initialization complete"
volumeMounts:
- name: shared-volume
mountPath: /work-dir
containers:
- name: app
image: ubuntu:20.04
command: ["/bin/bash", "-c"]
args:
- |
echo "Application starting..."
echo "Reading configuration:"
cat /work-dir/config/db.conf
cat /work-dir/config/api.conf
echo "Application running..."
sleep 3600
volumeMounts:
- name: shared-volume
mountPath: /work-dir
volumes:
- name: shared-volume
emptyDir: {}
在此配置中:
init-config
首先运行并创建配置文件。shared-volume
的卷。按 Ctrl+X
,然后按 Y
和 Enter
保存并退出。
让我们创建这个容器:
kubectl apply -f init-container-pod.yaml
你应该会看到:
pod/init-container-pod created
检查容器状态:
kubectl get pods init-container-pod
你应该会看到容器正在运行:
NAME READY STATUS RESTARTS AGE
init-container-pod 1/1 Running 0 30s
现在,让我们检查主容器的日志:
kubectl logs init-container-pod -c app
你应该会看到类似以下内容:
Application starting...
Reading configuration:
database_url=mysql://user:password@db:3306/mydb
api_key=1234567890
Application running...
这证实了初始化容器成功创建了配置文件,并且主容器能够读取这些文件。
让我们创建一个更实际的示例——一个在启动前检查数据库可用性的 Web 应用程序:
nano webapp-pod.yaml
添加以下内容:
apiVersion: v1
kind: Pod
metadata:
name: webapp-pod
spec:
initContainers:
- name: wait-for-db
image: busybox:1.28
command: ["/bin/sh", "-c"]
args:
- |
echo "Checking for database availability..."
## In a real scenario, this would check an actual database
## For this example, we'll simulate success after a short delay
sleep 5
echo "Database is available"
touch /tmp/db-ready
volumeMounts:
- name: shared-volume
mountPath: /tmp
containers:
- name: webapp
image: nginx:1.19
ports:
- containerPort: 80
command: ["/bin/sh", "-c"]
args:
- |
if [ -f /tmp/db-ready ]; then
echo "Database connection verified, starting web application..."
## Customize nginx configuration
echo "<h1>Web Application Started Successfully</h1>" > /usr/share/nginx/html/index.html
echo "<p>Connected to database</p>" >> /usr/share/nginx/html/index.html
## Start nginx
nginx -g 'daemon off;'
else
echo "Error: Database not available"
exit 1
fi
volumeMounts:
- name: shared-volume
mountPath: /tmp
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: shared-volume
emptyDir: {}
此配置:
按 Ctrl+X
,然后按 Y
和 Enter
保存并退出。
让我们创建这个容器:
kubectl apply -f webapp-pod.yaml
你应该会看到:
pod/webapp-pod created
等待片刻,让容器完全启动,然后检查其状态:
kubectl get pods webapp-pod
你应该会看到:
NAME READY STATUS RESTARTS AGE
webapp-pod 1/1 Running 0 30s
READY
列中的 1/1
表示就绪探针已成功。
让我们进行端口转发以访问 Web 应用程序:
kubectl port-forward webapp-pod 8080:80 &
此命令在后台运行(由于 &
)。现在,你可以使用 curl
访问 Web 应用程序:
curl http://localhost:8080
你应该会看到:
<h1>Web Application Started Successfully</h1>
<p>Connected to database</p>
这证实了应用程序已正确初始化,验证了数据库的可用性,并且现在正在提供流量。
停止端口转发进程:
pkill -f "kubectl port-forward"
在结束实验之前,让我们清理创建的资源:
kubectl delete pod basic-pod startup-command-pod modified-command-pod multi-command-pod liveness-probe-pod script-pod init-container-pod webapp-pod
你应该会看到:
pod "basic-pod" deleted
pod "startup-command-pod" deleted
pod "modified-command-pod" deleted
pod "multi-command-pod" deleted
pod "liveness-probe-pod" deleted
pod "script-pod" deleted
pod "init-container-pod" deleted
pod "webapp-pod" deleted
现在你已经学会了如何在 Kubernetes 容器启动时运行命令、执行多条命令、处理失败情况,以及在实际场景中应用最佳实践。
在本次实验中,你学习了如何在 Kubernetes 容器(Pod)启动时运行命令。你获得了以下方面的实践经验:
command
和 args
字段配置容器行为这些技能对于在 Kubernetes 环境中部署容器化应用程序至关重要。通过正确配置启动命令,你可以确保应用程序正确初始化、验证依赖项并优雅地处理错误。
在你继续 Kubernetes 学习之旅时,请记住,正确的应用程序初始化是构建可靠、可扩展和可维护系统的关键部分。