Kubernetes容器化:从基础到实践
立即解锁
发布时间: 2025-08-25 02:10:02 阅读量: 4 订阅数: 7 


Kubernetes for Developers: 实战容器编排与应用部署
### Kubernetes 资源表示与容器化实践
#### 1. Kubernetes 资源表示
Kubernetes 资源通常可以用 JSON 或 YAML 数据结构来表示。Kubernetes 允许保存这些文件,当需要运行软件时,可以使用 `kubectl deploy` 等命令,并提供之前创建的定义,以此来运行软件。在后续操作中,我们将使用 YAML 描述资源,并通过 `kubectl` 以 JSON 格式返回请求数据。所有 Kubernetes 资源的正式定义都使用 OpenAPI(也称为 Swagger)在源代码控制中维护,可在 [https://github.com/kubernetes/kubernetes/tree/master/api/swagger-spec](https://github.com/kubernetes/kubernetes/tree/master/api/swagger-spec) 查看。
#### 2. 容器镜像
使用 Kubernetes 的第一步是将软件放入容器中,Docker 是创建这些容器最简单的方式。下面我们通过拉取一个现有容器镜像来了解创建容器时的选择:
```bash
docker pull docker.io/jocatalin/kubernetes-bootcamp:v1
```
拉取过程中,会看到一系列带有神秘 ID 的文件下载信息,它们会并行更新:
```plaintext
v1: Pulling from jocatalin/kubernetes-bootcamp
5c90d4a2d1a8: Downloading 3.145MB/51.35MB
ab30c63719b1: Downloading 3.931MB/18.55MB
29d0bc1e8c52: Download complete
d4fe0dc68927: Downloading 2.896MB/13.67MB
dfa9e924f957: Waiting
```
下载完成后,输出会更新为提取,最后显示拉取完成:
```plaintext
v1: Pulling from jocatalin/kubernetes-bootcamp
5c90d4a2d1a8: Pull complete
ab30c63719b1: Pull complete
29d0bc1e8c52: Pull complete
d4fe0dc68927: Pull complete
dfa9e924f957: Pull complete
Digest: sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Status: Downloaded newer image for jocatalin/kubernetes-bootcamp:v1
```
这一过程实际上是 Docker 下载构成容器镜像的各层,将它们组合在一起并验证输出。Kubernetes 在运行软件时也会执行相同的过程,即下载镜像并运行。
运行 `docker images` 命令,可以看到拉取的镜像信息:
```plaintext
REPOSITORY TAG IMAGE ID CREATED
jocatalin/kubernetes-bootcamp v1 8fafd8af70e9 13 months ago
```
该镜像大小为 211MB,指定 `jocatalin/kubernetes-bootcamp:v1` 时,既指定了名称 `jocatalin/kubernetes-bootcamp`,也指定了标签 `v1`。此外,镜像还有一个唯一的 `IMAGE ID`(`8fafd8af70e9`)。如果指定镜像名称时未带标签,默认标签为 `latest`。
使用 `docker history` 命令可以深入查看镜像:
```bash
docker history jocatalin/kubernetes-bootcamp:v1
```
输出如下:
```plaintext
IMAGE CREATED CREATED BY SIZE
8fafd8af70e9 13 months ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "no... 0B
<missing> 13 months ago /bin/sh -c #(nop) COPY file:de8ef36ebbfd53... 742B
<missing> 13 months ago /bin/sh -c #(nop) EXPOSE 8080/tcp 0B
<missing> 13 months ago /bin/sh -c #(nop) CMD ["node"] 0B
<missing> 13 months ago /bin/sh -c buildDeps='xz-utils' && set... 41.5MB
<missing> 13 months ago /bin/sh -c #(nop) ENV NODE_VERSION=6.3.1 0B
<missing> 15 months ago /bin/sh -c #(nop) ENV NPM_CONFIG_LOGLEVEL=... 0B
<missing> 15 months ago /bin/sh -c set -ex && for key in 955... 80.8kB
<missing> 15 months ago /bin/sh -c apt-get update && apt-get insta... 44.7MB
<missing> 15 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 15 months ago /bin/sh -c #(nop) ADD file:76679eeb94129df... 125MB
```
这表明容器镜像是由多层组成的,每层都是一个命令执行的结果以及该命令对本地文件系统所做的更改。
镜像格式由 Docker 创建,现在由 OCI(开放容器倡议)镜像格式项目正式指定,可在 [https://github.com/opencontainers/image-spec](https://github.com/opencontainers/image-spec) 查看详细信息。容器镜像及其各层通常可在互联网上获取,本书示例使用的都是公开可用的镜像。也可以将 Kubernetes 集群配置为使用私有镜像仓库,相关文档可在 [https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) 查看。不过,这种设置更私密,但配置起来更复杂,因此我们将使用公开可用的镜像。
使用 `docker inspect` 命令可以查看容器镜像的详细信息:
```bash
docker inspect jocatalin/kubernetes-bootcamp:v1
```
输出的 JSON 信息包含了容器镜像的详细配置和运行代码所需的元数据。其中,`config` 部分指定了默认情况下运行容器时将调用的命令,通常称为 `Entrypoint`。例如,该镜像的 `Entrypoint` 为 `/bin/sh -c node server.js`,它定义了要执行的二进制文件及其参数,是指定要运行的内容和方式的关键。Kubernetes 可以使用相同的 `Entrypoint`,并通过命令和参数覆盖它,以运行软件或诊断工具。
#### 3. 容器注册表
在拉取容器时,我们引用了 Docker 的容器注册表 [https://www.docker.com/](https://www.docker.com/)。在使用 Kubernetes 或阅读相关文档时,还会经常看到另外两个常见的注册表:Google 的容器注册表 `gcr.io` 和 CoreOS 的容器注册表 `quay.io`。其他公司也在互联网上提供托管容器注册表,你也可以自己运行。目前,Docker 和 Quay 都为公共镜像提供免费托管,因此在文档和示例中经常会看到它们。这三个注册表也都提供私有镜像仓库选项,通常只需支付相对较小的订阅费用。
公开可用镜像的一个好处是可以方便地组合镜像,共享底层层。这也意味着可以检查这些层,并搜索常见层的安全漏洞。有几个开源项目致力于提供此类信息,也有一些公司帮助协调信息和扫描。如果你订阅了镜像仓库,其产品通常会包含漏洞扫描功能。
作为开发者,使用代码中的库时,要对其操作负责。同样,在指定整个容器时,也要对容器中包含的所有内容负责。很容易忘记软件所依赖的层,也可能没有时间跟踪所依赖软件的所有潜在安全漏洞和问题。像 Clair([https://github.com/coreos/clair](https://github.com/coreos/clair))这样的项目提供的安全扫描可以提供有关潜在漏洞的有用信息,建议考虑使用此类服务。
#### 4. 创建第一个容器
使用 Docker 软件和 `docker build` 命令可以轻松创建容器。该命令使用一个名为 `Dockerfile` 的清单来详细说明如何创建容器。
以下是创建最简单容器的步骤:
1. 创建一个名为 `Dockerfile` 的文件,并添加以下内容:
```Dockerfile
FROM alpine
CMD ["/bin/sh", "-c", "echo 'hello world'"]
```
2. 执行构建命令:
```bash
docker build .
```
如果看到以下响应:
```plaintext
"docker build" requires exactly 1 argument.
See 'docker build --help'.
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
```
则可能是命令中缺少 `.`,或者在与创建 `Dockerfile` 不同的目录中运行了该命令。`.` 表示告诉 Docker 在当前目录中查找 `Dockerfile`。
正常的构建输出如下:
```plaintext
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM alpine
latest: Pulling from library/alpine
88286f41530e: Pull complete
Digest: sha256:f006ecbb824d87947d0b51ab8488634bf69fe4094959d935c0c103f4820a417d
Status: Downloaded newer image for alpine:latest
---> 76da55c8019d
Step 2/2 : CMD /bin/sh -c echo 'hello world'
---> Running in 89c04e8c5d87
---> f5d273aa2dcb
Removing intermediate container 89c04e8c5d87
Successfully built f5d273aa2dcb
```
这个镜像只有一个 ID `f5d273aa2dcb`,没有名称,但足以让我们了解其工作原理。在本地运行此示例时,会得到一个唯一标识容器镜像的不同 ID。使用 `docker run` 命令运行容器镜像:
```bash
docker run f5d273aa2dcb
```
输出应为:
```plaintext
hello world
```
可以使用 `docker history` 和 `docker inspect` 命令进一步查看创建的镜像:
```bash
docker history f5d273aa2dcb
docker inspect f5d273aa2dcb
```
完成后,可以使用以下命令删除 Docker 镜像:
```bash
docker rmi f5d273aa2dcb
```
如果删除镜像时遇到错误(例如有停止的容器引用了本地镜像),可以添加 `-f` 强制删除:
```bash
docker rmi -f f5d237aa2dcb
```
#### 5. Dockerfile 命令
Docker 提供了关于如何编写 `Dockerfile` 的文档 [https://docs.docker.com/engine/reference/builder/](https://docs.docker.com/engine/reference/builder/),以及一组推荐的最佳实践 [https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/)。以下是一些构建自己的容器镜像时需要了解的重要 `Dockerfile` 命令:
1. **FROM**:描述用于构建容器的基础镜像,通常是 `Dockerfile` 中的第一个命令。Docker 最佳实践建议使用 Debian 作为基础 Linux 发行版,但也可以使用 Alpine Linux(体积小)、Ubuntu、Fedora 和 CentOS 等。还可以找到专门为支持特定语言(如 Node 或 Python)而构建的容器。不同基础镜像的大小差异很大,例如:
| REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
| --- | --- | --- | --- | --- |
| alpine | latest | 76da55c8019d | 2 days ago | 3.97MB |
| debian | latest | 72ef1cf971d1 | 2 days ago | 100MB |
| fedora | latest | ee17cf9e0828 | 2 days ago | 231MB |
| centos | latest | 196e0ce0c9fb | 27 hours ago | 197MB |
| ubuntu | latest | 8b72bba4485f | 2 days ago | 120MB |
| ubuntu | 16.10 | 7d3f705d307c | 8 weeks ago | 107MB |
| python | latest | 26acbad26a2c | 2 days ago | 690MB |
| node | latest | de1099630c13 | 24 hours ago | 673MB |
| java | latest | d23bdf5b1b1b | 8 months ago | 643MB |
可以在 [https://hub.docker.com/explore/](https://hub.docker.com/explore/) 探索这些和其他各种基础镜像。
2. **RUN**:描述在构建的容器镜像中运行的命令,最常用于添加依赖项或其他库。不同的基础镜像支持的命令不同,例如 `apt-get` 可在 Debian 和 Ubuntu 基础镜像中使用,但在 Alpine 或 Fedora 中不可用。如果 `RUN` 命令不可用或有拼写错误,运行 `docker build` 命令时会出错。例如:
```Dockerfile
FROM alpine
RUN apt-get install nodejs
```
构建时会输出错误:
```plaintext
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM alpine
---> 76da55c8019d
Step 2/2 : RUN apt-get install nodejs
---> Running in 58200129772d
/bin/sh: apt-get: not found
The /bin/sh -c apt-get install nodejs command returned a non-zero code: 127.
```
3. **ENV**:定义在调用容器镜像中的软件之前将持久设置的环境变量。这些变量在创建容器镜像时也会设置,可能会产生意外效果。如果需要为特定的 `RUN` 命令设置环境变量,最好在单个 `RUN` 命令中定义,而不是使用 `ENV` 命令。例如,使用 `ENV DEBIAN_FRONTEND non-interactive` 可能会影响后续在基于 Debian 的镜像中使用 `RUN apt-get install …` 命令。如果要为特定的 `RUN` 命令启用该设置,可以在单个 `RUN` 命令前临时添加环境变量,如:
```Dockerfile
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y ...
```
4. **COPY**:用于将本地文件添加到容器中,通常是将代码复制到容器镜像中运行的最有效方法。可以复制整个目录或单个文件。结合 `RUN` 命令,这可能是创建包含代码的容器镜像的主要方式。
5. **WORKDIR**:创建一个本地目录,并将该目录作为所有后续命令(如 `RUN`、`COPY` 等)的基础目录。对于期望在本地或相对目录中运行的 `RUN` 命令(如 Node.js 的 `npm` 安装工具)非常方便。
6. **LABEL**:添加可通过 `docker inspect` 查看的值,通常用于参考容器的负责人或内容。以前常用的 `MAINTAINER` 命令已被 `LABEL` 命令取代。标签基于基础镜像构建,是累加的,因此添加的任何标签都会包含在使用的基础镜像的标签中。
7. **CMD 和 ENTRYPOINT**:用于指定运行容器时要执行的内容。最常见的格式是 JSON 数组,第一个元素是要调用的命令,后续元素是该命令的参数。`CMD` 和 `ENTRYPOINT` 可以单独使用,也可以一起使用。单独使用时,使用 `CMD` 或 `ENTRYPOINT` 指定要执行的可执行文件及其所有参数;一起使用时,`ENTRYPOINT` 应仅为可执行文件,`CMD` 应为该可执行文件的参数。
通过以上步骤和命令,可以开始在 Kubernetes 中使用容器化的软件。在后续内容中,我们将继续介绍 Python 和 Node.js 示例,展示如何将简单的示例代码构建为容器并在 Kubernetes 中运行。
### Kubernetes 资源表示与容器化实践
#### 6. Python 示例 - 创建容器镜像
接下来,我们将通过一个 Python 示例,详细介绍如何将简单的 Python 代码构建为容器镜像,并在 Kubernetes 中运行。
##### 6.1 编写 Python 代码
首先,创建一个名为 `app.py` 的 Python 文件,以下是一个简单的 Flask 应用示例:
```python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
```
这个 Python 脚本创建了一个简单的 Flask Web 应用,监听 5000 端口并返回 `Hello, World!`。
##### 6.2 创建 Dockerfile
然后,在同一目录下创建 `Dockerfile`,用于构建容器镜像:
```Dockerfile
# 使用 Python 官方镜像作为基础镜像
FROM python:latest
# 设置工作目录
WORKDIR /app
# 复制当前目录下的所有文件到工作目录
COPY . /app
# 安装依赖
RUN pip install flask
# 暴露端口
EXPOSE 5000
# 定义启动命令
CMD ["python", "app.py"]
```
上述 `Dockerfile` 的步骤如下:
1. 使用 `FROM` 命令指定基础镜像为 Python 官方镜像。
2. 使用 `WORKDIR` 命令设置工作目录为 `/app`。
3. 使用 `COPY` 命令将当前目录下的所有文件复制到工作目录。
4. 使用 `RUN` 命令安装 Flask 依赖。
5. 使用 `EXPOSE` 命令暴露 5000 端口。
6. 使用 `CMD` 命令定义启动容器时执行的命令。
##### 6.3 构建容器镜像
在包含 `Dockerfile` 和 `app.py` 的目录下,执行以下命令构建容器镜像:
```bash
docker build -t python-app:latest .
```
其中,`-t` 参数用于指定镜像的标签,这里将镜像命名为 `python-app`,标签为 `latest`。`.` 表示使用当前目录作为构建上下文。
##### 6.4 运行容器
构建完成后,使用以下命令运行容器:
```bash
docker run -p 5000:5000 python-app:latest
```
`-p` 参数用于将容器的 5000 端口映射到主机的 5000 端口,这样就可以通过主机的 5000 端口访问 Flask 应用。
#### 7. Node.js 示例 - 创建容器镜像
同样,我们通过一个 Node.js 示例,展示如何将 Node.js 代码构建为容器镜像并在 Kubernetes 中运行。
##### 7.1 编写 Node.js 代码
创建一个名为 `server.js` 的 Node.js 文件,以下是一个简单的 HTTP 服务器示例:
```javascript
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!\n');
});
server.listen(3000, '0.0.0.0', () => {
console.log('Server running at http://0.0.0.0:3000/');
});
```
这个 Node.js 脚本创建了一个简单的 HTTP 服务器,监听 3000 端口并返回 `Hello, World!`。
##### 7.2 创建 Dockerfile
在同一目录下创建 `Dockerfile`:
```Dockerfile
# 使用 Node.js 官方镜像作为基础镜像
FROM node:latest
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制当前目录下的所有文件到工作目录
COPY . /app
# 暴露端口
EXPOSE 3000
# 定义启动命令
CMD ["node", "server.js"]
```
上述 `Dockerfile` 的步骤如下:
1. 使用 `FROM` 命令指定基础镜像为 Node.js 官方镜像。
2. 使用 `WORKDIR` 命令设置工作目录为 `/app`。
3. 先复制 `package.json` 和 `package-lock.json`,再执行 `npm install`,这样可以利用 Docker 缓存,提高构建效率。
4. 使用 `COPY` 命令将当前目录下的所有文件复制到工作目录。
5. 使用 `EXPOSE` 命令暴露 3000 端口。
6. 使用 `CMD` 命令定义启动容器时执行的命令。
##### 7.3 构建容器镜像
在包含 `Dockerfile` 和 `server.js` 的目录下,执行以下命令构建容器镜像:
```bash
docker build -t node-app:latest .
```
同样,`-t` 参数指定镜像的标签,`.` 表示使用当前目录作为构建上下文。
##### 7.4 运行容器
构建完成后,使用以下命令运行容器:
```bash
docker run -p 3000:3000 node-app:latest
```
`-p` 参数将容器的 3000 端口映射到主机的 3000 端口,以便通过主机的 3000 端口访问 Node.js 应用。
#### 8. 标签容器镜像
在构建和使用容器镜像时,标签非常重要。标签可以帮助我们区分不同版本的镜像,方便管理和部署。
##### 8.1 查看现有镜像标签
使用 `docker images` 命令可以查看本地已有的镜像及其标签:
```bash
docker images
```
输出示例如下:
```plaintext
REPOSITORY TAG IMAGE ID CREATED SIZE
python-app latest 123456789abc 1 hour ago 690MB
node-app latest abcdef123456 30 minutes ago 673MB
```
##### 8.2 为镜像添加标签
使用 `docker tag` 命令可以为现有镜像添加新的标签。例如,为 `python-app:latest` 镜像添加一个版本标签 `v1.0`:
```bash
docker tag python-app:latest python-app:v1.0
```
再次使用 `docker images` 命令查看,会看到多了一个带有新标签的镜像:
```plaintext
REPOSITORY TAG IMAGE ID CREATED SIZE
python-app latest 123456789abc 1 hour ago 690MB
python-app v1.0 123456789abc 1 hour ago 690MB
node-app latest abcdef123456 30 minutes ago 673MB
```
##### 8.3 推送镜像到注册表
如果需要将镜像推送到公共或私有注册表,可以使用 `docker push` 命令。以 Docker Hub 为例,首先需要登录到 Docker Hub:
```bash
docker login
```
然后将带有标签的镜像推送到 Docker Hub:
```bash
docker push python-app:v1.0
```
需要注意的是,在推送之前,需要确保镜像的名称符合 Docker Hub 的命名规则,通常为 `用户名/镜像名:标签`。
#### 9. 总结
通过以上内容,我们详细介绍了 Kubernetes 资源的表示方式,以及如何将软件容器化并在 Kubernetes 中运行。具体步骤和要点总结如下:
1. **Kubernetes 资源表示**:Kubernetes 资源可以用 JSON 或 YAML 数据结构表示,使用 `kubectl` 命令结合定义文件来运行软件。
2. **容器镜像**:使用 Docker 创建容器镜像,了解镜像的层结构、大小、标签等信息,以及如何查看和管理镜像。
3. **容器注册表**:常见的容器注册表有 Docker、Google 的 `gcr.io` 和 CoreOS 的 `quay.io`,可以选择公共或私有镜像仓库。
4. **创建容器**:使用 `docker build` 命令和 `Dockerfile` 来创建容器,掌握 `Dockerfile` 中的各种命令,如 `FROM`、`RUN`、`COPY` 等。
5. **示例实践**:通过 Python 和 Node.js 示例,展示了如何将代码构建为容器镜像并运行。
6. **标签管理**:为镜像添加标签,方便管理和部署,使用 `docker tag` 和 `docker push` 命令进行标签管理和镜像推送。
通过这些步骤和方法,可以更好地在 Kubernetes 中使用容器化的软件,提高开发和部署的效率。
以下是创建容器的流程 mermaid 流程图:
```mermaid
graph LR
A[创建 Dockerfile] --> B[编写基础镜像和命令]
B --> C[使用 docker build 构建镜像]
C --> D[使用 docker run 运行容器]
D --> E[使用 docker tag 添加标签]
E --> F[使用 docker push 推送镜像]
```
希望这些内容能帮助你更好地理解和应用 Kubernetes 以及容器化技术。在实际应用中,可以根据具体需求和场景进行调整和优化。
0
0
复制全文
相关推荐










