Switch language name 'zh' to 'zh-cn'

This is the first step to rename 'zh' to 'zh-cn'. There are several reasons why we rename the language name.

- The upstream docsy theme changed the language name, leading to many warnings during site build;
  The side-effect is that the i18n strings are no longer working.
- We believe renaming the language is the right thing to do, because this move can make room for other variants of Chinese language, such as 'zh-tw', 'zh-sg' etc.

There would be several follow-ups to this PR, such as fixing the intra-site links, adding redirects etc.

We will lock up changes to zh/zh-cn pages for the moment, until this one gets in.

This PR is based on commit cdad0a7342.
This commit is contained in:
Qiming Teng
2022-06-10 20:25:27 +08:00
parent 3d345b1816
commit c52818c03d
1347 changed files with 8 additions and 6 deletions
+123
View File
@@ -0,0 +1,123 @@
---
title: 教程
main_menu: true
no_list: true
weight: 60
content_type: concept
---
<!--
title: Tutorials
main_menu: true
no_list: true
weight: 60
content_type: concept
-->
<!-- overview -->
<!--
This section of the Kubernetes documentation contains tutorials.
A tutorial shows how to accomplish a goal that is larger than a single
[task](/docs/tasks/). Typically a tutorial has several sections,
each of which has a sequence of steps.
Before walking through each tutorial, you may want to bookmark the
[Standardized Glossary](/docs/reference/glossary/) page for later references.
-->
Kubernetes 文档的这一部分包含教程。
每个教程展示了如何完成一个比单个[任务](/zh/docs/tasks/)更大的目标。
通常一个教程有几个部分,每个部分都有一系列步骤。在浏览每个教程之前,
你可能希望将[标准化术语表](/zh/docs/reference/glossary/)页面添加到书签,供以后参考。
<!-- body -->
<!--
## Basics
* [Kubernetes Basics](/docs/tutorials/kubernetes-basics/) is an in-depth interactive tutorial that helps you understand the Kubernetes system and try out some basic Kubernetes features.
* [Introduction to Kubernetes (edX)](https://www.edx.org/course/introduction-kubernetes-linuxfoundationx-lfs158x#)
* [Hello Minikube](/docs/tutorials/hello-minikube/)
-->
## 基础知识 {#basics}
* [Kubernetes 基础知识](/zh/docs/tutorials/Kubernetes-Basics/)
是一个深入的交互式教程,帮助你理解 Kubernetes 系统,并尝试一些基本的 Kubernetes 特性。
* [Kubernetes 介绍 (edX)](https://www.edx.org/course/introduction-kubernetes-linuxfoundationx-lfs158x#)
* [你好 Minikube](/zh/docs/tutorials/hello-minikube/)
<!--
## Configuration
* [Example: Configuring a Java Microservice](/docs/tutorials/configuration/configure-java-microservice/)
* [Configuring Redis Using a ConfigMap](/docs/tutorials/configuration/configure-redis-using-configmap/)
-->
## 配置 {#configuration}
* [示例:配置 Java 微服务](/zh/docs/tutorials/configuration/configure-java-microservice/)
* [使用 ConfigMap 配置 Redis](/zh/docs/tutorials/configuration/configure-redis-using-configmap/)
<!--
## Stateless Applications
* [Exposing an External IP Address to Access an Application in a Cluster](/docs/tutorials/stateless-application/expose-external-ip-address/)
* [Example: Deploying PHP Guestbook application with MongoDB](/docs/tutorials/stateless-application/guestbook/)
-->
## 无状态应用程序 {#stateless-applications}
* [公开外部 IP 地址访问集群中的应用程序](/zh/docs/tutorials/stateless-application/expose-external-ip-address/)
* [示例:使用 Redis 部署 PHP 留言板应用程序](/zh/docs/tutorials/stateless-application/guestbook/)
<!--
## Stateful Applications
* [StatefulSet Basics](/docs/tutorials/stateful-application/basic-stateful-set/)
* [Example: WordPress and MySQL with Persistent Volumes](/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/)
* [Example: Deploying Cassandra with Stateful Sets](/docs/tutorials/stateful-application/cassandra/)
* [Running ZooKeeper, A CP Distributed System](/docs/tutorials/stateful-application/zookeeper/)
-->
## 有状态应用程序 {#stateful-applications}
* [StatefulSet 基础](/zh/docs/tutorials/stateful-application/basic-stateful-set/)
* [示例:WordPress 和 MySQL 使用持久卷](/zh/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/)
* [示例:使用有状态集部署 Cassandra](/zh/docs/tutorials/stateful-application/cassandra/)
* [运行 ZooKeeperCP 分布式系统](/zh/docs/tutorials/stateful-application/zookeeper/)
<!--
## Services
* [Using Source IP](/docs/tutorials/services/source-ip/)
-->
## 服务 {#services}
* [使用源 IP](/zh/docs/tutorials/services/source-ip/)
<!--
## Security
* [Apply Pod Security Standards at Cluster level](/docs/tutorials/security/cluster-level-pss/)
* [Apply Pod Security Standards at Namespace level](/docs/tutorials/security/ns-level-pss/)
* [AppArmor](/zh/docs/tutorials/security/apparmor/)
* [seccomp](/zh/docs/tutorials/security/seccomp/)
-->
## 安全 {#security}
* [在集群级别应用 Pod 安全标准](/zh/docs/tutorials/security/cluster-level-pss/)
* [在名字空间级别应用 Pod 安全标准](/zh/docs/tutorials/security/ns-level-pss/)
* [AppArmor](/zh/docs/tutorials/security/apparmor/)
* [seccomp](/zh/docs/tutorials/security/seccomp/)
## {{% heading "whatsnext" %}}
<!--
If you would like to write a tutorial, see
[Content Page Types](/docs/contribute/style/page-content-types/)
for information about the tutorial page.
-->
如果你要编写教程,请参阅[内容页面类型](/zh/docs/contribute/style/page-content-types/)
以获取有关教程页面类型的信息。
@@ -0,0 +1,4 @@
---
title: "配置"
weight: 30
---
@@ -0,0 +1,10 @@
---
title: "示例:配置 java 微服务"
weight: 10
---
<!--
---
title: "Example: Configuring a Java Microservice"
weight: 10
---
-->
@@ -0,0 +1,37 @@
---
title: "互动教程 - 配置 java 微服务"
weight: 20
---
<!--
---
title: "Interactive Tutorial - Configuring a Java Microservice"
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<div class="katacoda">
<div class="katacoda__alert">
<!-- To interact with the Terminal, please use the desktop/tablet version -->
如需要与终端交互,请使用台式机/平板电脑版
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/9" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;"></div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,93 @@
---
title: "使用 MicroProfile、ConfigMaps、Secrets 实现外部化应用配置"
content_type: tutorial
weight: 10
---
<!--
---
title: "Externalizing config using MicroProfile, ConfigMaps and Secrets"
content_type: tutorial
weight: 10
---
-->
<!-- overview -->
<!--
In this tutorial you will learn how and why to externalize your microservices configuration. Specifically, you will learn how to use Kubernetes ConfigMaps and Secrets to set environment variables and then consume them using MicroProfile Config.
-->
在本教程中,你会学到如何以及为什么要实现外部化微服务应用配置。
具体来说,你将学习如何使用 Kubernetes ConfigMaps 和 Secrets 设置环境变量,
然后在 MicroProfile config 中使用它们。
## {{% heading "prerequisites" %}}
<!--
### Creating Kubernetes ConfigMaps & Secrets
There are several ways to set environment variables for a Docker container in Kubernetes, including: Dockerfile, kubernetes.yml, Kubernetes ConfigMaps, and Kubernetes Secrets. In the tutorial, you will learn how to use the latter two for setting your environment variables whose values will be injected into your microservices. One of the benefits for using ConfigMaps and Secrets is that they can be re-used across multiple containers, including being assigned to different environment variables for the different containers.
-->
### 创建 Kubernetes ConfigMaps 和 Secrets {#creating-kubernetes-configmaps-secrets}
在 Kubernetes 中,为 docker 容器设置环境变量有几种不同的方式,比如:
Dockerfile、kubernetes.yml、Kubernetes ConfigMaps、和 Kubernetes Secrets。
在本教程中,你将学到怎么用后两个方式去设置你的环境变量,而环境变量的值将注入到你的微服务里。
使用 ConfigMaps 和 Secrets 的一个好处是他们能在多个容器间复用,
比如赋值给不同的容器中的不同环境变量。
<!--
ConfigMaps are API Objects that store non-confidential key-value pairs. In the Interactive Tutorial you will learn how to use a ConfigMap to store the application's name. For more information regarding ConfigMaps, you can find the documentation [here](/docs/tasks/configure-pod-container/configure-pod-configmap/).
Although Secrets are also used to store key-value pairs, they differ from ConfigMaps in that they're intended for confidential/sensitive information and are stored using Base64 encoding. This makes secrets the appropriate choice for storing such things as credentials, keys, and tokens, the former of which you'll do in the Interactive Tutorial. For more information on Secrets, you can find the documentation [here](/docs/concepts/configuration/secret/).
-->
ConfigMaps 是存储非机密键值对的 API 对象。
在互动教程中,你会学到如何用 ConfigMap 来保存应用名字。
ConfigMap 的更多信息,你可以在[这里](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/)找到文档。
Secrets 尽管也用来存储键值对,但区别于 ConfigMaps 的是:它针对机密/敏感数据,且存储格式为 Base64 编码。
secrets 的这种特性使得它适合于存储证书、密钥、令牌,上述内容你将在交互教程中实现。
Secrets 的更多信息,你可以在[这里](/zh/docs/concepts/configuration/secret/)找到文档。
<!--
### Externalizing Config from Code
Externalized application configuration is useful because configuration usually changes depending on your environment. In order to accomplish this, we'll use Java's Contexts and Dependency Injection (CDI) and MicroProfile Config. MicroProfile Config is a feature of MicroProfile, a set of open Java technologies for developing and deploying cloud-native microservices.
-->
### 从代码外部化配置
外部化应用配置之所以有用处,是因为配置常常根据环境的不同而变化。
为了实现此功能,我们用到了 Java 上下文和依赖注入(Contexts and Dependency Injection, CDI)、MicroProfile 配置。
MicroProfile config 是 MicroProfile 的功能特性,
是一组开放 Java 技术,用于开发、部署云原生微服务。
<!--
CDI provides a standard dependency injection capability enabling an application to be assembled from collaborating, loosely-coupled beans. MicroProfile Config provides apps and microservices a standard way to obtain config properties from various sources, including the application, runtime, and environment. Based on the source's defined priority, the properties are automatically combined into a single set of properties that the application can access via an API. Together, CDI & MicroProfile will be used in the Interactive Tutorial to retrieve the externally provided properties from the Kubernetes ConfigMaps and Secrets and get injected into your application code.
Many open source frameworks and runtimes implement and support MicroProfile Config. Throughout the interactive tutorial, you'll be using Open Liberty, a flexible open-source Java runtime for building and running cloud-native apps and microservices. However, any MicroProfile compatible runtime could be used instead.
-->
CDI 提供一套标准的依赖注入能力,使得应用程序可以由相互协作的、松耦合的 beans 组装而成。
MicroProfile Config 为 app 和微服务提供从各种来源,比如应用、运行时、环境,获取配置参数的标准方法。
基于来源定义的优先级,属性可以自动的合并到单独一组应用可以通过 API 访问到的属性。
CDI & MicroProfile 都会被用在互动教程中,
用来从 Kubernetes ConfigMaps 和 Secrets 获得外部提供的属性,并注入应用程序代码中。
很多开源框架、运行时支持 MicroProfile Config。
对于整个互动教程,你都可以使用开放的库、灵活的开源 Java 运行时,去构建并运行云原生的 apps 和微服务。
然而,任何 MicroProfile 兼容的运行时都可以用来做替代品。
## {{% heading "objectives" %}}
<!--
* Create a Kubernetes ConfigMap and Secret
* Inject microservice configuration using MicroProfile Config
-->
* 创建 Kubernetes ConfigMap 和 Secret
* 使用 MicroProfile Config 注入微服务配置
<!-- lessoncontent -->
<!--
## Example: Externalizing config using MicroProfile, ConfigMaps and Secrets
### [Start Interactive Tutorial](/docs/tutorials/configuration/configure-java-microservice/configure-java-microservice-interactive/)
-->
## 示例:使用 MicroProfile、ConfigMaps、Secrets 实现外部化应用配置
### [启动互动教程](/zh/docs/tutorials/configuration/configure-java-microservice/configure-java-microservice-interactive/)
@@ -0,0 +1,376 @@
---
title: 使用 ConfigMap 来配置 Redis
content_type: tutorial
---
<!--
reviewers:
- eparis
- pmorie
title: Configuring Redis using a ConfigMap
content_type: tutorial
-->
<!-- overview -->
<!--
This page provides a real world example of how to configure Redis using a ConfigMap and builds upon the [Configure a Pod to Use a ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/) task.
-->
这篇文档基于[配置 Pod 以使用 ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/)
这个任务,提供了一个使用 ConfigMap 来配置 Redis 的真实案例。
## {{% heading "objectives" %}}
<!--
* Create a ConfigMap with Redis configuration values
* Create a Redis Pod that mounts and uses the created ConfigMap
* Verify that the configuration was correctly applied.
-->
* 使用 Redis 配置的值创建一个 ConfigMap
* 创建一个 Redis Pod,挂载并使用创建的 ConfigMap
* 验证配置已经被正确应用
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
<!--
* The example shown on this page works with `kubectl` 1.14 and above.
* Understand [Configure a Pod to Use a ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/).
-->
* 此页面上显示的示例适用于 `kubectl` 1.14 及以上的版本。
* 理解[配置 Pod 以使用 ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/)。
<!-- lessoncontent -->
<!--
## Real World Example: Configuring Redis using a ConfigMap
Follow the steps below to configure a Redis cache using data stored in a ConfigMap.
First create a ConfigMap with an empty configuration block:
-->
## 真实世界的案例:使用 ConfigMap 来配置 Redis {#real-world-example-configuring-redis-using-a-configmap}
按照下面的步骤,使用 ConfigMap 中的数据来配置 Redis 缓存。
首先创建一个配置模块为空的 ConfigMap:
```shell
cat <<EOF >./example-redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: ""
EOF
```
<!--
Apply the ConfigMap created above, along with a Redis pod manifest:
-->
应用上面创建的 ConfigMap 以及 Redis pod 清单:
```shell
kubectl apply -f example-redis-config.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml
```
<!--
Examine the contents of the Redis pod manifest and note the following:
* A volume named `config` is created by `spec.volumes[1]`
* The `key` and `path` under `spec.volumes[1].items[0]` exposes the `redis-config` key from the
`example-redis-config` ConfigMap as a file named `redis.conf` on the `config` volume.
* The `config` volume is then mounted at `/redis-master` by `spec.containers[0].volumeMounts[1]`.
This has the net effect of exposing the data in `data.redis-config` from the `example-redis-config`
ConfigMap above as `/redis-master/redis.conf` inside the Pod.
-->
检查 Redis pod 清单的内容,并注意以下几点:
*`spec.volumes[1]` 创建一个名为 `config` 的卷。
* `spec.volumes[1].items[0]` 下的 `key``path` 会将来自 `example-redis-config`
ConfigMap 中的 `redis-config` 密钥公开在 `config` 卷上一个名为 `redis-config` 的文件中。
* 然后 `config` 卷被 `spec.containers[0].volumeMounts[1]` 挂载在 `/redis-master`
这样做的最终效果是将上面 `example-redis-config` 配置中 `data.redis-config`
的数据作为 Pod 中的 `/redis-master/redis.conf` 公开。
{{< codenew file="pods/config/redis-pod.yaml" >}}
<!--
Examine the created objects:
-->
检查创建的对象:
```shell
kubectl get pod/redis configmap/example-redis-config
```
<!--
You should see the following output:
-->
你应该可以看到以下输出:
```
NAME READY STATUS RESTARTS AGE
pod/redis 1/1 Running 0 8s
NAME DATA AGE
configmap/example-redis-config 1 14s
```
<!--
Recall that we left `redis-config` key in the `example-redis-config` ConfigMap blank:
-->
回顾一下,我们在 `example-redis-config` ConfigMap 保留了空的 `redis-config` 键:
```shell
kubectl describe configmap/example-redis-config
```
<!--
You should see an empty `redis-config` key:
-->
你应该可以看到一个空的 `redis-config` 键:
```shell
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
```
<!--
Use `kubectl exec` to enter the pod and run the `redis-cli` tool to check the current configuration:
-->
使用 `kubectl exec` 进入 pod,运行 `redis-cli` 工具检查当前配置:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It should show the default value of 0:
-->
它应该显示默认值 0
```shell
1) "maxmemory"
2) "0"
```
<!--
Similarly, check `maxmemory-policy`:
-->
同样,查看 `maxmemory-policy`
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
Which should also yield its default value of `noeviction`:
-->
它也应该显示默认值 `noeviction`
```shell
1) "maxmemory-policy"
2) "noeviction"
```
<!--
Now let's add some configuration values to the `example-redis-config` ConfigMap:
-->
现在,向 `example-redis-config` ConfigMap 添加一些配置:
{{< codenew file="pods/config/example-redis-config.yaml" >}}
<!--
Apply the updated ConfigMap:
-->
应用更新的 ConfigMap:
```shell
kubectl apply -f example-redis-config.yaml
```
<!--
Confirm that the ConfigMap was updated:
-->
确认 ConfigMap 已更新:
```shell
kubectl describe configmap/example-redis-config
```
<!--
You should see the configuration values we just added:
-->
你应该可以看到我们刚刚添加的配置:
```shell
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
----
maxmemory 2mb
maxmemory-policy allkeys-lru
```
<!--
Check the Redis Pod again using `redis-cli` via `kubectl exec` to see if the configuration was applied:
-->
通过 `kubectl exec` 使用 `redis-cli` 再次检查 Redis Pod,查看是否已应用配置:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It remains at the default value of 0:
-->
它保持默认值 0
```shell
1) "maxmemory"
2) "0"
```
<!--
Similarly, `maxmemory-policy` remains at the `noeviction` default setting:
-->
同样,`maxmemory-policy` 保留为默认设置 `noeviction`
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
Returns:
-->
返回:
```shell
1) "maxmemory-policy"
2) "noeviction"
```
<!--
The configuration values have not changed because the Pod needs to be restarted to grab updated
values from associated ConfigMaps. Let's delete and recreate the Pod:
-->
配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
让我们删除并重新创建 Pod
```shell
kubectl delete pod redis
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml
```
<!--
Now re-check the configuration values one last time:
-->
现在,最后一次重新检查配置值:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It should now return the updated value of 2097152:
-->
现在,它应该返回更新后的值 2097152:
```shell
1) "maxmemory"
2) "2097152"
```
<!--
Similarly, `maxmemory-policy` has also been updated:
-->
同样,`maxmemory-policy` 也已更新:
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
It now reflects the desired value of `allkeys-lru`:
-->
现在它反映了期望值 `allkeys-lru`
```shell
1) "maxmemory-policy"
2) "allkeys-lru"
```
<!--
Clean up your work by deleting the created resources:
-->
删除创建的资源,清理你的工作:
```shell
kubectl delete pod/redis configmap/example-redis-config
```
## {{% heading "whatsnext" %}}
<!--
* Learn more about [ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/).
-->
* 了解有关 [ConfigMaps](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/) 的更多信息。
@@ -0,0 +1,503 @@
---
title: 你好,Minikube
content_type: tutorial
weight: 5
menu:
main:
title: "Get Started"
weight: 10
post: >
<p>准备好动手操作了么?构建一个简单的 Kubernetes 集群来运行示例应用。</p>
card:
name: tutorials
weight: 10
---
<!--
title: Hello Minikube
content_type: tutorial
weight: 5
menu:
main:
title: "Get Started"
weight: 10
post: >
<p>Ready to get your hands dirty? Build a simple Kubernetes cluster that runs a sample app.</p>
card:
name: tutorials
weight: 10
-->
<!-- overview -->
<!--
This tutorial shows you how to run a sample app
on Kubernetes using minikube and Katacoda.
Katacoda provides a free, in-browser Kubernetes environment.
-->
本教程向你展示如何使用 Minikube 和 Katacoda
在 Kubernetes 上运行一个应用示例。Katacoda 提供免费的浏览器内 Kubernetes 环境。
<!--
{{< note >}}
You can also follow this tutorial if you've installed minikube locally.
See [minikube start](https://minikube.sigs.k8s.io/docs/start/) for installation instructions.
{{< /note >}}
-->
{{< note >}}
如果你已在本地安装 Minikube,也可以按照本教程操作。
安装指南参阅 [minikube start](https://minikube.sigs.k8s.io/docs/start/) 。
{{< /note >}}
## {{% heading "objectives" %}}
<!--
* Deploy a sample application to minikube.
* Run the app.
* View application logs.
-->
* 将一个示例应用部署到 Minikube。
* 运行应用程序。
* 查看应用日志
## {{% heading "prerequisites" %}}
<!--
This tutorial provides a container image that uses NGINX to echo back all the requests.
-->
本教程提供了容器镜像,使用 NGINX 来对所有请求做出回应:
<!-- lessoncontent -->
<!--
## Create a minikube cluster
1. Click **Launch Terminal**
-->
## 创建 Minikube 集群
1. 点击 **启动终端**
{{< kat-button >}}
<!--
If you installed minikube locally, run `minikube start`. Before you run `minikube dashboard`, you should open a new terminal, start `minikube dashboard` there, and then switch back to the main terminal.
-->
{{< note >}}
如果你在本地安装了 Minikube,运行 `minikube start`
在运行 `minikube dashboard` 之前,你应该打开一个新终端,
在此启动 `minikube dashboard` ,然后切换回主终端。
{{< /note >}}
<!--
2. Open the Kubernetes dashboard in a browser:
-->
2. 在浏览器中打开 Kubernetes 仪表板(Dashboard):
```shell
minikube dashboard
```
<!--
3. Katacoda environment only: At the top of the terminal pane, click the plus sign, and then click **Select port to view on Host 1**.
-->
3. 仅限 Katacoda 环境:在终端窗口的顶部,单击加号,然后单击 **选择要在主机 1 上查看的端口**。
<!--
4. Katacoda environment only: Type `30000`, and then click **Display Port**.
-->
4. 仅限 Katacoda 环境:输入“30000”,然后单击 **显示端口**。
<!--
The `dashboard` command enables the dashboard add-on and opens the proxy in the default web browser.
You can create Kubernetes resources on the dashboard such as Deployment and Service.
If you are running in an environment as root, see [Open Dashboard with URL](#open-dashboard-with-url).
By default, the dashboard is only accessible from within the internal Kubernetes virtual network.
The `dashboard` command creates a temporary proxy to make the dashboard accessible from outside the Kubernetes virtual network.
To stop the proxy, run `Ctrl+C` to exit the process.
After the command exits, the dashboard remains running in the Kubernetes cluster.
You can run the `dashboard` command again to create another proxy to access the dashboard.
-->
{{< note >}}
`dashboard` 命令启用仪表板插件,并在默认的 Web 浏览器中打开代理。
你可以在仪表板上创建 Kubernetes 资源,例如 Deployment 和 Service。
如果你以 root 用户身份在环境中运行,
请参见[使用 URL 打开仪表板](#open-dashboard-with-url)。
默认情况下,仪表板只能从内部 Kubernetes 虚拟网络中访问。
`dashboard` 命令创建一个临时代理,使仪表板可以从 Kubernetes 虚拟网络外部访问。
要停止代理,请运行 `Ctrl+C` 退出该进程。仪表板仍在运行中。
命令退出后,仪表板仍然在 Kubernetes 集群中运行。
你可以再次运行 `dashboard` 命令创建另一个代理来访问仪表板。
{{< /note >}}
<!--
## Open Dashboard with URL
-->
## 使用 URL 打开仪表板
<!--
If you don't want to open a web browser, run the dashboard command with the `--url` flag to emit a URL:
-->
如果你不想打开 Web 浏览器,请使用 `--url` 标志运行显示板命令以得到 URL:
```shell
minikube dashboard --url
```
<!--
## Create a Deployment
A Kubernetes [*Pod*](/docs/concepts/workloads/pods/) is a group of one or more Containers,
tied together for the purposes of administration and networking. The Pod in this
tutorial has only one Container. A Kubernetes
[*Deployment*](/docs/concepts/workloads/controllers/deployment/) checks on the health of your
Pod and restarts the Pod's Container if it terminates. Deployments are the
recommended way to manage the creation and scaling of Pods.
-->
## 创建 Deployment
Kubernetes [*Pod*](/zh/docs/concepts/workloads/pods/) 是由一个或多个
为了管理和联网而绑定在一起的容器构成的组。 本教程中的 Pod 只有一个容器。
Kubernetes [*Deployment*](/zh/docs/concepts/workloads/controllers/deployment/)
检查 Pod 的健康状况,并在 Pod 中的容器终止的情况下重新启动新的容器。
Deployment 是管理 Pod 创建和扩展的推荐方法。
<!--
1. Use the `kubectl create` command to create a Deployment that manages a Pod. The
Pod runs a Container based on the provided Docker image.
-->
1. 使用 `kubectl create` 命令创建管理 Pod 的 Deployment。该 Pod 根据提供的 Docker
镜像运行 Container。
```shell
kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4
```
<!--
2. View the Deployment:
-->
2. 查看 Deployment
```shell
kubectl get deployments
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
NAME READY UP-TO-DATE AVAILABLE AGE
hello-node 1/1 1 1 1m
```
<!--
3. View the Pod:
-->
3. 查看 Pod
```shell
kubectl get pods
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
NAME READY STATUS RESTARTS AGE
hello-node-5f76cf6ccf-br9b5 1/1 Running 0 1m
```
<!--
4. View cluster events:
-->
4. 查看集群事件:
```shell
kubectl get events
```
<!--
5. View the `kubectl` configuration:
-->
5. 查看 `kubectl` 配置:
```shell
kubectl config view
```
<!--
For more information about `kubectl`commands, see the
[kubectl overview](/docs/reference/kubectl/).
-->
{{< note >}}
有关 `kubectl` 命令的更多信息,请参阅 [kubectl 概述](/zh/docs/reference/kubectl/)。
{{< /note >}}
<!--
## Create a Service
By default, the Pod is only accessible by its internal IP address within the
Kubernetes cluster. To make the `hello-node` Container accessible from outside the
Kubernetes virtual network, you have to expose the Pod as a
Kubernetes [*Service*](/docs/concepts/services-networking/service/).
-->
## 创建 Service
默认情况下,Pod 只能通过 Kubernetes 集群中的内部 IP 地址访问。
要使得 `hello-node` 容器可以从 Kubernetes 虚拟网络的外部访问,你必须将 Pod
暴露为 Kubernetes [*Service*](/zh/docs/concepts/services-networking/service/)。
<!--
1. Expose the Pod to the public internet using the `kubectl expose` command:
-->
1. 使用 `kubectl expose` 命令将 Pod 暴露给公网:
```shell
kubectl expose deployment hello-node --type=LoadBalancer --port=8080
```
<!--
The `--type=LoadBalancer` flag indicates that you want to expose your Service
outside of the cluster.
The application code inside the image `k8s.gcr.io/echoserver` only listens on TCP port 8080. If you used
`kubectl expose` to expose a different port, clients could not connect to that other port.
-->
这里的 `--type=LoadBalancer` 参数表明你希望将你的 Service 暴露到集群外部。
镜像 `k8s.gcr.io/echoserver` 中的应用程序代码仅监听 TCP 8080 端口。
如果你用 `kubectl expose` 暴露了其它的端口,客户端将不能访问其它端口。
<!--
2. View the Service you created:
-->
2. 查看你创建的 Service
```shell
kubectl get services
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.108.144.78 <pending> 8080:30369/TCP 21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23m
```
<!--
On cloud providers that support load balancers,
an external IP address would be provisioned to access the Service. On minikube,
the `LoadBalancer` type makes the Service accessible through the `minikube service`
command.
-->
对于支持负载均衡器的云服务平台而言,平台将提供一个外部 IP 来访问该服务。
在 Minikube 上,`LoadBalancer` 使得服务可以通过命令 `minikube service` 访问。
<!--
3. Run the following command:
-->
3. 运行下面的命令:
```shell
minikube service hello-node
```
<!--
4. Katacoda environment only: Click the plus sign, and then click **Select port to view on Host 1**.
-->
4. 仅限 Katacoda 环境:单击加号,然后单击 **选择要在主机 1 上查看的端口**。
<!--
5. Katacoda environment only: Note the 5-digit port number displayed opposite to `8080` in services output. This port number is randomly generated and it can be different for you. Type your number in the port number text box, then click Display Port. Using the example from earlier, you would type `30369`.
This opens up a browser window that serves your app and shows the app's response.
-->
5. 仅限 Katacoda 环境:请注意在 service 输出中与 `8080` 对应的长度为 5 位的端口号。
此端口号是随机生成的,可能与你的不同。
在端口号文本框中输入你自己的端口号,然后单击显示端口。
对应于上面的例子,需要输入 `30369`。
这将打开一个浏览器窗口,为你的应用程序提供服务并显示应用的响应。
<!--
## Enable addons
The minikube tool includes a set of built-in {{< glossary_tooltip text="addons" term_id="addons" >}} that can be enabled, disabled and opened in the local Kubernetes environment.
1. List the currently supported addons:
-->
## 启用插件
Minikube 有一组内置的 {{< glossary_tooltip text="插件" term_id="addons" >}}
可以在本地 Kubernetes 环境中启用、禁用和打开。
1. 列出当前支持的插件:
```shell
minikube addons list
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
addon-manager: enabled
dashboard: enabled
default-storageclass: enabled
efk: disabled
freshpod: disabled
gvisor: disabled
helm-tiller: disabled
ingress: disabled
ingress-dns: disabled
logviewer: disabled
metrics-server: disabled
nvidia-driver-installer: disabled
nvidia-gpu-device-plugin: disabled
registry: disabled
registry-creds: disabled
storage-provisioner: enabled
storage-provisioner-gluster: disabled
```
<!--
2. Enable an addon, for example, `metrics-server`:
-->
2. 启用插件,例如 `metrics-server`
```shell
minikube addons enable metrics-server
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
The 'metrics-server' addon is enabled
```
<!--
3. View the Pod and Service you created:
-->
3. 查看创建的 Pod 和 Service
```shell
kubectl get pod,svc -n kube-system
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
NAME READY STATUS RESTARTS AGE
pod/coredns-5644d7b6d9-mh9ll 1/1 Running 0 34m
pod/coredns-5644d7b6d9-pqd2t 1/1 Running 0 34m
pod/metrics-server-67fb648c5 1/1 Running 0 26s
pod/etcd-minikube 1/1 Running 0 34m
pod/influxdb-grafana-b29w8 2/2 Running 0 26s
pod/kube-addon-manager-minikube 1/1 Running 0 34m
pod/kube-apiserver-minikube 1/1 Running 0 34m
pod/kube-controller-manager-minikube 1/1 Running 0 34m
pod/kube-proxy-rnlps 1/1 Running 0 34m
pod/kube-scheduler-minikube 1/1 Running 0 34m
pod/storage-provisioner 1/1 Running 0 34m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metrics-server ClusterIP 10.96.241.45 <none> 80/TCP 26s
service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 34m
service/monitoring-grafana NodePort 10.99.24.54 <none> 80:30002/TCP 26s
service/monitoring-influxdb ClusterIP 10.111.169.94 <none> 8083/TCP,8086/TCP 26s
```
<!--
4. Disable `metrics-server`:
-->
4. 禁用 `metrics-server`
```shell
minikube addons disable metrics-server
```
<!--
The output is similar to:
-->
输出结果类似于这样:
```
metrics-server was successfully disabled
```
<!--
## Clean up
Now you can clean up the resources you created in your cluster:
-->
## 清理
现在可以清理你在集群中创建的资源:
```shell
kubectl delete service hello-node
kubectl delete deployment hello-node
```
<!--
Optionally, stop the Minikube virtual machine (VM):
-->
可选地,停止 Minikube 虚拟机(VM):
```shell
minikube stop
```
<!--
Optionally, delete the Minikube VM:
-->
可选地,删除 Minikube 虚拟机(VM):
```shell
minikube delete
```
## {{% heading "whatsnext" %}}
<!--
* Learn more about [Deployment objects](/docs/concepts/workloads/controllers/deployment/).
* Learn more about [Deploying applications](/docs/tasks/run-application/run-stateless-application-deployment/).
* Learn more about [Service objects](/docs/concepts/services-networking/service/).
-->
* 进一步了解 [Deployment 对象](/zh/docs/concepts/workloads/controllers/deployment/)。
* 进一步了解[部署应用](/zh/docs/tasks/run-application/run-stateless-application-deployment/)。
* 进一步了解 [Service 对象](/zh/docs/concepts/services-networking/service/)。
@@ -0,0 +1,118 @@
---
title: 学习 Kubernetes 基础知识
linkTitle: 学习 Kubernetes 基础知识
no_list: true
weight: 10
card:
name: tutorials
weight: 20
title: 基础知识介绍
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-9">
<h2>Kubernetes 基础</h2>
<p>本教程介绍了 Kubernetes 集群编排系统的基础知识。每个模块包含关于 Kubernetes 主要特性和概念的一些背景信息,并包括一个在线互动教程。这些互动教程让你可以自己管理一个简单的集群及其容器化应用程序。</p>
<p>使用互动教程,你可以学习:</p>
<ul>
<li>在集群上部署容器化应用程序</li>
<li>弹性部署</li>
<li>使用新的软件版本,更新容器化应用程序</li>
<li>调试容器化应用程序</li>
</ul>
<p>教程 Katacoda 在你的浏览器中运行一个虚拟终端,在浏览器中运行 Minikube,这是一个可在任何地方小规模本地部署的 Kubernetes 集群。不需要安装任何软件或进行任何配置;每个交互性教程都直接从你的网页浏览器上运行。</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-9">
<h2>Kubernetes 可以为你做些什么?</h2>
<p>通过现代的 Web 服务,用户希望应用程序能够 24/7 全天候使用,开发人员希望每天可以多次发布部署新版本的应用程序。 容器化可以帮助软件包达成这些目标,使应用程序能够以简单快速的方式发布和更新,而无需停机。Kubernetes 帮助你确保这些容器化的应用程序在你想要的时间和地点运行,并帮助应用程序找到它们需要的资源和工具。Kubernetes 是一个可用于生产的开源平台,根据 Google 容器集群方面积累的经验,以及来自社区的最佳实践而设计。</p>
</div>
</div>
<br>
<div id="basics-modules" class="content__modules">
<h2>Kubernetes 基础模块</h2>
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_01.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/"><h5>1. 创建一个 Kubernetes 集群</h5></a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_02.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/"><h5>2. 部署应用程序</h5></a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/explore/explore-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_03.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/explore/explore-intro/"><h5>3. 应用程序探索</h5></a>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/expose/expose-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_04.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/expose/expose-intro/"><h5>4. 应用外部可见</h5></a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/scale/scale-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_05.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/scale/scale-intro/"><h5>5. 应用可扩展</h5></a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="thumbnail">
<a href="/zh/docs/tutorials/kubernetes-basics/update/update-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_06.svg?v=1469803628347" alt=""></a>
<div class="caption">
<a href="/zh/docs/tutorials/kubernetes-basics/update/update-intro/"><h5>6. 应用更新</h5></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,10 @@
---
title: 创建集群
weight: 10
---
<!--
Learn about Kubernetes {{< glossary_tooltip text="cluster" term_id="cluster" length="all" >}} and create a simple cluster using Minikube.
-->
了解 Kubernetes {{<glossary_tooltip text="集群" term_id="cluster" length="all" >}}并使用 Minikube
创建一个简单的集群。
@@ -0,0 +1,53 @@
---
title: 交互式教程 - 创建集群
weight: 20
---
<!--
---
title: Interactive Tutorial - Creating a Cluster
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<div class="katacoda">
<div class="katacoda__alert">
<!--
To interact with the Terminal, please use the desktop/tablet version
-->
要与终端交互,请使用桌面/平板
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/1" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;"></div>
</div>
<div class="row">
<div class="col-md-12">
<!--
<a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/" role="button">Continue to Module 2<span class="btn__next"></span></a>
-->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/" role="button">继续阅读第二单元<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,108 @@
---
title: 使用 Minikube 创建集群
weight: 10
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<h3>目标</h3>
<ul>
<li>了解 Kubernetes 集群。</li>
<li>了解 Minikube 。</li>
<li>使用在线终端开启一个 Kubernetes 集群。</li>
</ul>
</div>
<div class="col-md-8">
<h3> Kubernetes 集群</h3>
<p>
<b> Kubernetes 协调一个高可用计算机集群,每个计算机作为独立单元互相连接工作。</b> Kubernetes 中的抽象允许你将容器化的应用部署到集群,而无需将它们绑定到某个特定的独立计算机。为了使用这种新的部署模型,应用需要以将应用与单个主机分离的方式打包:它们需要被容器化。与过去的那种应用直接以包的方式深度与主机集成的部署模型相比,容器化应用更灵活、更可用。<b> Kubernetes 以更高效的方式跨集群自动分发和调度应用容器。</b> Kubernetes 是一个开源平台,并且可应用于生产环境。
</p>
<p>一个 Kubernetes 集群包含两种类型的资源:
<ul>
<li><b> Master </b>调度整个集群</li>
<li><b> Nodes </b>负责运行应用</li>
</ul>
</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<h3>总结:</h3>
<ul>
<li> Kubernetes 集群</li>
<li> Minikube </li>
</ul>
</div>
<div class="content__box content__box_fill">
<p><i>
Kubernetes 是一个生产级别的开源平台,可协调在计算机集群内和跨计算机集群的应用容器的部署(调度)和执行.
</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<h2 style="color: #3771e3;">集群图</h2>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_01_cluster.svg"></p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<p><b> Master 负责管理整个集群。</b> Master 协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。</p>
<p><b> Node 是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色</b> 每个Node都有 Kubelet , 它管理 Node 而且是 Node 与 Master 通信的代理。 Node 还应该具有用于​​处理容器操作的工具,例如 Docker 或 rkt 。处理生产级流量的 Kubernetes 集群至少应具有三个 Node,因为如果一个 Node 出现故障其对应的 etcd 成员和控制平面实例都会丢失,并且冗余会受到影响。 你可以通过添加更多控制平面节点来降低这种风险 。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<p><i> Master 管理集群,Node 用于托管正在运行的应用。</i></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p>在 Kubernetes 上部署应用时,你告诉 Master 启动应用容器。 Master 就编排容器在集群的 Node 上运行。<b> Node 使用 Master 暴露的 Kubernetes API 与 Master 通信。</b>终端用户也可以使用 Kubernetes API 与集群交互。</p>
<p> Kubernetes 既可以部署在物理机上也可以部署在虚拟机上。你可以使用 Minikube 开始部署 Kubernetes 集群。 Minikube 是一种轻量级的 Kubernetes 实现,可在本地计算机上创建 VM 并部署仅包含一个节点的简单集群。 Minikube 可用于 Linux macOS 和 Windows 系统。Minikube CLI 提供了用于引导集群工作的多种操作,包括启动、停止、查看状态和删除。在本教程里,你可以使用预装有 Minikube 的在线终端进行体验。</p>
<p>既然你已经知道 Kubernetes 是什么,让我们转到在线教程并启动我们的第一个 Kubernetes 集群!</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-interactive/" role="button"> 启动交互教程 <span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,4 @@
---
title: 部署应用
weight: 20
---
@@ -0,0 +1,45 @@
---
title: 交互式教程 - 部署应用
weight: 20
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<br>
<div class="katacoda">
<!-- <div class="katacoda__alert">
To interact with the Terminal, please use the desktop/tablet version
</div> -->
<div class="katacoda__alert">
要与终端进行交互,请使用桌面/平板电脑版本
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/7" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<!-- <a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/explore/explore-intro/" role="button">Continue to Module 3<span class="btn__next"></span></a> -->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/explore/explore-intro/" role="button">继续阅读第3单元<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,136 @@
---
title: 使用 kubectl 创建 Deployment
weight: 10
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<!-- <h3>Objectives</h3> -->
<h3>目标</h3>
<!-- <ul>
<li>Learn about application Deployments.</li>
<li>Deploy your first app on Kubernetes with kubectl.</li>
</ul> -->
<ul>
<li>学习了解应用的部署</li>
<li>使用 kubectl 在 Kubernetes 上部署第一个应用</li>
</ul>
</div>
<div class="col-md-8">
<!-- <h3>Kubernetes Deployments</h3> -->
<h3>Kubernetes 部署</h3>
<!-- <p>
Once you have a running Kubernetes cluster, you can deploy your containerized applications on top of it.
To do so, you create a Kubernetes <b>Deployment</b> configuration. The Deployment instructs Kubernetes
how to create and update instances of your application. Once you've created a Deployment, the Kubernetes
master schedules mentioned application instances onto individual Nodes in the cluster.
</p> -->
<p>
一旦运行了 Kubernetes 集群,就可以在其上部署容器化应用程序。
为此,你需要创建 Kubernetes <b> Deployment </b>配置。Deployment 指挥 Kubernetes 如何创建和更新应用程序的实例。创建 Deployment 后,Kubernetes master 将应用程序实例调度到集群中的各个节点上。
</p>
<!-- <p>Once the application instances are created, a Kubernetes Deployment Controller continuously monitors those instances. If the Node hosting an instance goes down or is deleted, the Deployment controller replaces the instance with an instance on another Node in the cluster. <b>This provides a self-healing mechanism to address machine failure or maintenance.</b></p> -->
<p>创建应用程序实例后,Kubernetes Deployment 控制器会持续监视这些实例。 如果托管实例的节点关闭或被删除,则 Deployment 控制器会将该实例替换为集群中另一个节点上的实例。 <b>这提供了一种自我修复机制来解决机器故障维护问题。</b></p>
<!-- <p>In a pre-orchestration world, installation scripts would often be used to start applications, but they did not allow recovery from machine failure. By both creating your application instances and keeping them running across Nodes, Kubernetes Deployments provide a fundamentally different approach to application management. </p> -->
<p>在没有 Kubernetes 这种编排系统之前,安装脚本通常用于启动应用程序,但它们不允许从机器故障中恢复。通过创建应用程序实例并使它们在节点之间运行, Kubernetes Deployments 提供了一种与众不同的应用程序管理方法。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<!-- <h3>Summary:</h3> -->
<h3>总结:</h3>
<ul>
<li>Deployments</li>
<li>Kubectl</li>
</ul>
</div>
<div class="content__box content__box_fill">
<!-- <p><i>
A Deployment is responsible for creating and updating instances of your application
</i></p> -->
<p><i>
Deployment 负责创建和更新应用程序的实例
</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <h2 style="color: #3771e3;">Deploying your first app on Kubernetes</h2> -->
<h2 style="color: #3771e3;">部署你在 Kubernetes 上的第一个应用程序</h2>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_02_first_app.svg"></p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <p>You can create and manage a Deployment by using the Kubernetes command line interface, <b>Kubectl</b>. Kubectl uses the Kubernetes API to interact with the cluster. In this module, you'll learn the most common Kubectl commands needed to create Deployments that run your applications on a Kubernetes cluster.</p> -->
<p>你可以使用 Kubernetes 命令行界面 <b>Kubectl</b> 创建和管理 Deployment。Kubectl 使用 Kubernetes API 与集群进行交互。在本单元中,你将学习创建在 Kubernetes 集群上运行应用程序的 Deployment 所需的最常见的 Kubectl 命令。</p>
<!-- <p>When you create a Deployment, you'll need to specify the container image for your application and the number of replicas that you want to run. You can change that information later by updating your Deployment; Modules <a href="/docs/tutorials/kubernetes-basics/scale-intro/">5</a> and <a href="/docs/tutorials/kubernetes-basics/update-intro/">6</a> of the bootcamp discuss how you can scale and update your Deployments.</p> -->
<p>创建 Deployment 时,你需要指定应用程序的容器映像以及要运行的副本数。你可以稍后通过更新 Deployment 来更改该信息; 模块 <a href="/zh/docs/tutorials/kubernetes-basics/scale-intro/">5</a><a href="/zh/docs/tutorials/kubernetes-basics/update-intro/">6</a> 讨论了如何扩展和更新 Deployments。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!-- <p><i> Applications need to be packaged into one of the supported container formats in order to be deployed on Kubernetes </i></p> -->
<p><i> 应用程序需要打包成一种受支持的容器格式,以便部署在 Kubernetes 上 </i></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<!-- <p>For our first Deployment, we'll use a Node.js application packaged in a Docker container.
To create the Node.js application and deploy the Docker container, follow the instructions from the
<a href="/docs/tutorials/hello-minikube/">Hello Minikube tutorial</a>.</p>
<p>Now that you know what Deployments are, let's go to the online tutorial and deploy our first app!</p> -->
<p>对于我们的第一次部署,我们将使用打包在 Docker 容器中的 Node.js 应用程序。
要创建 Node.js 应用程序并部署 Docker 容器,请按照
<a href="/zh/docs/tutorials/hello-minikube/">你好 Minikube 教程</a>.</p>
<p>现在你已经了解了 Deployment 的内容,让我们转到在线教程并部署我们的第一个应用程序!</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-interactive/" role="button">开始交互式教程 <span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,4 @@
---
title: 了解你的应用
weight: 30
---
@@ -0,0 +1,54 @@
---
title: 交互式教程-了解你的应用
weight: 20
---
<!--
---
title: Interactive Tutorial - Exploring Your App
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<br>
<div class="katacoda">
<!--
<div class="katacoda__alert">
To interact with the Terminal, please use the desktop/tablet version
</div>
-->
<div class="katacoda__alert">
要与终端交互,请使用桌面/平板 版本
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/4" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/expose/expose-intro/" role="button">继续阅读第4单元<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,222 @@
---
title: 查看 pod 和工作节点
weight: 10
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<!--
<h3>Objectives</h3>
-->
<h3>目标</h3>
<ul>
<!--
<li>Learn about Kubernetes Pods.</li>
<li>Learn about Kubernetes Nodes.</li>
<li>Troubleshoot deployed applications.</li>
-->
<li>了解 Kubernetes Pod。</li>
<li>了解 Kubernetes 工作节点。</li>
<li>对已部署的应用故障排除。</li>
</ul>
</div>
<div class="col-md-8">
<!--
<h2>Kubernetes Pods</h2>
-->
<h2>Kubernetes Pods</h2>
<!--
<p>When you created a Deployment in Module <a href="/docs/tutorials/kubernetes-basics/deploy-intro/">2</a>, Kubernetes created a <b>Pod</b> to host your application instance. A Pod is a Kubernetes abstraction that represents a group of one or more application containers (such as Docker), and some shared resources for those containers. Those resources include:</p>
-->
<p>在模块 <a href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/">2</a>创建 Deployment 时, Kubernetes 添加了一个 <b>Pod</b> 来托管你的应用实例。Pod 是 Kubernetes 抽象出来的,表示一组一个或多个应用程序容器(如 Docker),以及这些容器的一些共享资源。这些资源包括:</p>
<!--
<ul>
<li>Shared storage, as Volumes</li>
<li>Networking, as a unique cluster IP address</li>
<li>Information about how to run each container, such as the container image version or specific ports to use</li>
</ul>
-->
<ul>
<li>共享存储,当作卷</li>
<li>网络,作为唯一的集群 IP 地址</li>
<li>有关每个容器如何运行的信息,例如容器映像版本或要使用的特定端口。</li>
</ul>
<!--
<p>A Pod models an application-specific "logical host" and can contain different application containers which are relatively tightly coupled. For example, a Pod might include both the container with your Node.js app as well as a different container that feeds the data to be published by the Node.js webserver. The containers in a Pod share an IP Address and port space, are always co-located and co-scheduled, and run in a shared context on the same Node.</p>
-->
<p>Pod 为特定于应用程序的“逻辑主机”建模,并且可以包含相对紧耦合的不同应用容器。例如,Pod 可能既包含带有 Node.js 应用的容器,也包含另一个不同的容器,用于提供 Node.js 网络服务器要发布的数据。Pod 中的容器共享 IP 地址和端口,始终位于同一位置并且共同调度,并在同一工作节点上的共享上下文中运行。</p>
<!--
<p>Pods are the atomic unit on the Kubernetes platform. When we create a Deployment on Kubernetes, that Deployment creates Pods with containers inside them (as opposed to creating containers directly). Each Pod is tied to the Node where it is scheduled, and remains there until termination (according to restart policy) or deletion. In case of a Node failure, identical Pods are scheduled on other available Nodes in the cluster.</p>
-->
<p>Pod是 Kubernetes 平台上的原子单元。 当我们在 Kubernetes 上创建 Deployment 时,该 Deployment 会在其中创建包含容器的 Pod (而不是直接创建容器)。每个 Pod 都与调度它的工作节点绑定,并保持在那里直到终止(根据重启策略)或删除。 如果工作节点发生故障,则会在集群中的其他可用工作节点上调度相同的 Pod。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<!--
<h3>Summary:</h3>
-->
<h3>总结:</h3>
<ul>
<li>Pods</li>
<li>工作节点</li>
<!--
<li>Kubectl main commands</li>
-->
<li>Kubectl 主要命令</li>
</ul>
</div>
<div class="content__box content__box_fill">
<!--
<p><i>
A Pod is a group of one or more application containers (such as Docker) and includes shared storage (volumes), IP address and information about how to run them.
</i></p>
-->
<p><i>
Pod 是一组一个或多个应用程序容器(例如 Docker),包括共享存储(卷), IP 地址和有关如何运行它们的信息。
</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<h2 style="color: #3771e3;">Pods overview</h2>
-->
<h2 style="color: #3771e3;">Pod 概览</h2>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_03_pods.svg"></p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<h2>Nodes</h2>
<p>A Pod always runs on a <b>Node</b>. A Node is a worker machine in Kubernetes and may be either a virtual or a physical machine, depending on the cluster. Each Node is managed by the Master. A Node can have multiple pods, and the Kubernetes master automatically handles scheduling the pods across the Nodes in the cluster. The Master's automatic scheduling takes into account the available resources on each Node.</p>
<p>Every Kubernetes Node runs at least:</p>
<ul>
<li>Kubelet, a process responsible for communication between the Kubernetes Master and the Node; it manages the Pods and the containers running on a machine.</li>
<li>A container runtime (like Docker) responsible for pulling the container image from a registry, unpacking the container, and running the application.</li>
</ul>
-->
<h2>工作节点</h2>
<p>一个 pod 总是运行在 <b>工作节点</b>。工作节点是 Kubernetes 中的参与计算的机器,可以是虚拟机或物理计算机,具体取决于集群。每个工作节点由主节点管理。工作节点可以有多个 pod ,Kubernetes 主节点会自动处理在集群中的工作节点上调度 pod 。 主节点的自动调度考量了每个工作节点上的可用资源。</p>
<p>每个 Kubernetes 工作节点至少运行:</p>
<ul>
<li>Kubelet,负责 Kubernetes 主节点和工作节点之间通信的过程; 它管理 Pod 和机器上运行的容器。</li>
<li>容器运行时(如 Docker)负责从仓库中提取容器镜像,解压缩容器以及运行应用程序。</li>
</ul>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!--
<p><i> Containers should only be scheduled together in a single Pod if they are tightly coupled and need to share resources such as disk. </i></p>
-->
<p><i>如果它们紧耦合并且需要共享磁盘等资源,这些容器应在一个 Pod 中编排。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<h2 style="color: #3771e3;">Node overview</h2>
-->
<h2 style="color: #3771e3;">工作节点概览</h2>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_03_nodes.svg"></p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<h2>Troubleshooting with kubectl</h2>
-->
<h2>使用 kubectl 进行故障排除</h2>
<!--
<p>In Module <a href="/docs/tutorials/kubernetes-basics/deploy/deploy-intro/">2</a>, you used Kubectl command-line interface. You'll continue to use it in Module 3 to get information about deployed applications and their environments. The most common operations can be done with the following kubectl commands:</p>
-->
<p>在模块 <a href="/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/">2</a>,你使用了 Kubectl 命令行界面。 你将继续在第3单元中使用它来获取有关已部署的应用程序及其环境的信息。 最常见的操作可以使用以下 kubectl 命令完成:</p>
<!--
<ul>
<li><b>kubectl get</b> - list resources</li>
<li><b>kubectl describe</b> - show detailed information about a resource</li>
<li><b>kubectl logs</b> - print the logs from a container in a pod</li>
<li><b>kubectl exec</b> - execute a command on a container in a pod</li>
</ul>
-->
<ul>
<li><b>kubectl get</b> - 列出资源</li>
<li><b>kubectl describe</b> - 显示有关资源的详细信息</li>
<li><b>kubectl logs</b> - 打印 pod 和其中容器的日志</li>
<li><b>kubectl exec</b> - 在 pod 中的容器上执行命令</li>
</ul>
<!--
<p>You can use these commands to see when applications were deployed, what their current statuses are, where they are running and what their configurations are.</p>
-->
<p>你可以使用这些命令查看应用程序的部署时间,当前状态,运行位置以及配置。</p>
<!--
<p>Now that we know more about our cluster components and the command line, let's explore our application.</p>
-->
<p>现在我们了解了有关集群组件和命令行的更多信息,让我们来探索一下我们的应用程序。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!--
<p><i> A node is a worker machine in Kubernetes and may be a VM or physical machine, depending on the cluster. Multiple Pods can run on one Node. </i></p>
-->
<p><i>工作节点是 Kubernetes 中的负责计算的机器,可能是VM或物理计算机,具体取决于集群。多个 Pod 可以在一个工作节点上运行。 </i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<!--
<a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/explore/explore-interactive/" role="button">Start Interactive Tutorial <span class="btn__next"></span></a>
-->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/explore/explore-interactive/" role="button"> 开始交互式教程 <span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,4 @@
---
title: 公开地暴露你的应用
weight: 40
---
@@ -0,0 +1,50 @@
---
title: 交互式教程 - 暴露你的应用
weight: 20
---
<!--
---
title: Interactive Tutorial - Exposing Your App
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<div class="katacoda">
<div class="katacoda__alert">
<!--
To interact with the Terminal, please use the desktop/tablet version
-->
要与终端交互,请使用台式机/平板电脑
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/8" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/scale/scale-intro/" role="button">继续阅读第5单元<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,142 @@
---
<!--title: Using a Service to Expose Your App-->
title: 使用 Service 暴露你的应用
weight: 10
---
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<!-- <h3>Objectives</h3>-->
<h3>目标</h3>
<ul>
<!-- <li>Learn about a Service in Kubernetes</li>-->
<!-- <li>Understand how labels and LabelSelector objects relate to a Service</li>-->
<!-- <li>Expose an application outside a Kubernetes cluster using a Service</li>-->
<li>了解 Kubernetes 中的 Service </li>
<li>了解 标签(Label) 和 标签选择器(Label Selector) 对象如何与 Service 关联</li>
<li>在 Kubernetes 集群外用 Service 暴露应用</li>
</ul>
</div>
<div class="col-md-8">
<!-- <h3>Overview of Kubernetes Services</h3>-->
<h3>Kubernetes Service 总览</h3>
<!-- <p>Kubernetes <a href="/docs/concepts/workloads/pods/pod-overview/">Pods</a> are mortal. Pods in fact have a <a href="/docs/concepts/workloads/pods/pod-lifecycle/">lifecycle</a>. When a worker node dies, the Pods running on the Node are also lost. A <a href="/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> might then dynamically drive the cluster back to desired state via creation of new Pods to keep your application running. As another example, consider an image-processing backend with 3 replicas. Those replicas are exchangeable; the front-end system should not care about backend replicas or even if a Pod is lost and recreated. That said, each Pod in a Kubernetes cluster has a unique IP address, even Pods on the same Node, so there needs to be a way of automatically reconciling changes among Pods so that your applications continue to function.</p>-->
<p> Kubernetes <a href="/zh/docs/concepts/workloads/pods/">Pod</a> 是转瞬即逝的。 Pod 实际上拥有 <a href="/zh/docs/concepts/workloads/pods/pod-lifecycle/">生命周期</a>。 当一个工作 Node 挂掉后, 在 Node 上运行的 Pod 也会消亡。 <a href="/zh/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> 会自动地通过创建新的 Pod 驱动集群回到目标状态,以保证应用程序正常运行。 换一个例子,考虑一个具有3个副本数的用作图像处理的后端程序。这些副本是可替换的; 前端系统不应该关心后端副本,即使 Pod 丢失或重新创建。也就是说,Kubernetes 集群中的每个 Pod (即使是在同一个 Node 上的 Pod )都有一个唯一的 IP 地址,因此需要一种方法自动协调 Pod 之间的变更,以便应用程序保持运行。</p>
<!-- <p>A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them. Services enable a loose coupling between dependent Pods. A Service is defined using YAML <a href="/docs/concepts/configuration/overview/#general-configuration-tips">(preferred)</a> or JSON, like all Kubernetes objects. The set of Pods targeted by a Service is usually determined by a <i>LabelSelector</i> (see below for why you might want a Service without including <code>selector</code> in the spec).</p>-->
<p> Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。Service 使从属 Pod 之间的松耦合成为可能。 和其他 Kubernetes 对象一样, Service 用 YAML <a href="/zh/docs/concepts/configuration/overview/#general-configuration-tips">(更推荐)</a> 或者 JSON 来定义. Service 下的一组 Pod 通常由 <i>LabelSelector</i> (请参阅下面的说明为什么你可能想要一个 spec 中不包含<code>selector</code>的服务)来标记。</p>
<!-- <p>Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. Services allow your applications to receive traffic. Services can be exposed in different ways by specifying a <code>type</code> in the ServiceSpec:</p>-->
<p>尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service ,这些 IP 不会暴露在集群外部。Service 允许你的应用程序接收流量。Service 也可以用在 ServiceSpec 标记<code>type</code>的方式暴露</p>
<ul>
<!-- <li><i>ClusterIP</i> (default) - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.</li>-->
<!-- <li><i>NodePort</i> - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using <code>&lt;NodeIP&gt;:&lt;NodePort&gt;</code>. Superset of ClusterIP.</li>-->
<!-- <li><i>LoadBalancer</i> - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. Superset of NodePort.</li>-->
<!-- <li><i>ExternalName</i> - Exposes the Service using an arbitrary name (specified by <code>externalName</code> in the spec) by returning a CNAME record with the name. No proxy is used. This type requires v1.7 or higher of <code>kube-dns</code>.</li>-->
<li><i>ClusterIP</i> (默认) - 在集群的内部 IP 上公开 Service 。这种类型使得 Service 只能从集群内访问。</li>
<li><i>NodePort</i> - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用<code>&lt;NodeIP&gt;:&lt;NodePort&gt;</code> 从集群外部访问 Service。是 ClusterIP 的超集。</li>
<li><i>LoadBalancer</i> - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。</li>
<li><i>ExternalName</i> - 通过返回带有该名称的 CNAME 记录,使用任意名称(由 spec 中的<code>externalName</code>指定)公开 Service。不使用代理。这种类型需要<code>kube-dns</code>的v1.7或更高版本。</li>
</ul>
<!-- <p>More information about the different types of Services can be found in the <a href="/docs/tutorials/services/source-ip/">Using Source IP</a> tutorial. Also see <a href="/docs/concepts/services-networking/connect-applications-service">Connecting Applications with Services</a>.</p>-->
<p>更多关于不同 Service 类型的信息可以在<a href="/zh/docs/tutorials/services/source-ip/">使用源 IP </a> 教程。 也请参阅 <a href="/zh/docs/concepts/services-networking/connect-applications-service">连接应用程序和 Service </a></p>
<!-- <p>Additionally, note that there are some use cases with Services that involve not defining <code>selector</code> in the spec. A Service created without <code>selector</code> will also not create the corresponding Endpoints object. This allows users to manually map a Service to specific endpoints. Another possibility why there may be no selector is you are strictly using <code>type: ExternalName</code>.</p>-->
<p>另外,需要注意的是有一些 Service 的用例没有在 spec 中定义<code>selector</code>。 一个没有<code>selector</code>创建的 Service 也不会创建相应的端点对象。这允许用户手动将服务映射到特定的端点。没有 selector 的另一种可能是你严格使用<code>type: ExternalName</code>来标记。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<!-- <h3>Summary</h3>-->
<h3>总结</h3>
<ul>
<!-- <li>Exposing Pods to external traffic</li>-->
<!-- <li>Load balancing traffic across multiple Pods</li>-->
<!-- <li>Using labels</li>-->
<li>将 Pod 暴露给外部通信</li>
<li>跨多个 Pod 的负载均衡</li>
<li>使用标签(Label)</li>
</ul>
</div>
<div class="content__box content__box_fill">
<!-- <p><i>A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods.</i></p>-->
<p><i>Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<h3>Service 和 Label</h3>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_04_services.svg" width="150%" height="150%"></p>
</div>
</div>
<div class="row">
<div class="col-md-8">
<!-- <p>A Service routes traffic across a set of Pods. Services are the abstraction that allow pods to die and replicate in Kubernetes without impacting your application. Discovery and routing among dependent Pods (such as the frontend and backend components in an application) is handled by Kubernetes Services.</p>-->
<p>Service 通过一组 Pod 路由通信。Service 是一种抽象,它允许 Pod 死亡并在 Kubernetes 中复制,而不会影响应用程序。在依赖的 Pod (如应用程序中的前端和后端组件)之间进行发现和路由是由Kubernetes Service 处理的。</p>
<!-- <p>Services match a set of Pods using <a href="/docs/concepts/overview/working-with-objects/labels">labels and selectors</a>, a grouping primitive that allows logical operation on objects in Kubernetes. Labels are key/value pairs attached to objects and can be used in any number of ways:</p>-->
<p>Service 匹配一组 Pod 是使用 <a href="/zh/docs/concepts/overview/working-with-objects/labels">标签(Label)和选择器(Selector)</a>, 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。标签(Label)是附加在对象上的键/值对,可以以多种方式使用:</p>
<ul>
<!-- <li>Designate objects for development, test, and production</li>-->
<!-- <li>Embed version tags</li>-->
<!-- <li>Classify an object using tags</li>-->
<li>指定用于开发,测试和生产的对象</li>
<li>嵌入版本标签</li>
<li>使用 Label 将对象进行分类</li>
</ul>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!-- <p><i>You can create a Service at the same time you create a Deployment by using<br><code>&#45;&#45;expose</code> in kubectl.</i></p>-->
<p><i>你也可以在创建 Deployment 的同时用 <code>--expose</code>创建一个 Service 。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_04_labels.svg"></p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <p>Labels can be attached to objects at creation time or later on. They can be modified at any time. Let's expose our application now using a Service and apply some labels.</p>-->
<p> 标签(Label)可以在创建时或之后附加到对象上。他们可以随时被修改。现在使用 Service 发布我们的应用程序并添加一些 Label 。</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<!-- <a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/expose/expose-interactive/" role="button">Start Interactive Tutorial<span class="btn__next"></span></a>-->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/expose/expose-interactive/" role="button">开始交互式教程<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,4 @@
---
title: 缩放你的应用
weight: 50
---
@@ -0,0 +1,48 @@
---
title: 交互教程 - 缩放你的应用
weight: 20
---
<!--
---
title: Interactive Tutorial - Scaling Your App
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<div class="katacoda">
<div class="katacoda__alert">
<!--
To interact with the Terminal, please use the desktop/tablet version
-->
与终端交互,请使用桌面/平板电脑版本
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/5" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/update/update-intro/" role="button"><!--Continue to Module 6-->继续参阅第6单元<span class="btn__next"></span></a>
</div>
</div>
</main>
<a class="scrolltop" href="#top"></a>
</div>
</body>
</html>
@@ -0,0 +1,139 @@
---
title: 运行应用程序的多个实例
weight: 10
---
<!--
---
title: Running Multiple Instances of Your App
weight: 10
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<!-- <h3>Objectives</h3> -->
<h3>目标</h3>
<ul>
<!-- <li>Scale an app using kubectl.</li> -->
<li>用 kubectl 扩缩应用程序</li>
</ul>
</div>
<div class="col-md-8">
<!-- <h3>Scaling an application</h3> -->
<h3>扩缩应用程序</h3>
<!-- <p>In the previous modules we created a <a href="/docs/concepts/workloads/controllers/deployment/"> Deployment</a>,
and then exposed it publicly via a <a href="/docs/concepts/services-networking/service/">Service</a>.
The Deployment created only one Pod for running our application. When traffic increases, we will need to scale the application to keep up with user demand.</p> -->
<p>在之前的模块中,我们创建了一个 <a href="/zh/docs/concepts/workloads/controllers/deployment/"> Deployment</a>,然后通过 <a href="/zh/docs/concepts/services-networking/service/">Service</a>让其可以开放访问。Deployment 仅为跑这个应用程序创建了一个 Pod。 当流量增加时,我们需要扩容应用程序满足用户需求。</p>
<!-- <p><b>Scaling</b> is accomplished by changing the number of replicas in a Deployment</p> -->
<p><b>扩缩</b> 是通过改变 Deployment 中的副本数量来实现的。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<!-- <h3>Summary:</h3> -->
<h3>小结:</h3>
<ul>
<!-- <li>Scaling a Deployment</li> -->
<li>扩缩一个 Deployment</li>
</ul>
</div>
<div class="content__box content__box_fill">
<!-- <p><i> You can create from the start a Deployment with multiple instances using the --replicas parameter for the kubectl run command </i></p> -->
<p><i> 在运行 kubectl run 命令时,你可以通过设置 --replicas 参数来设置 Deployment 的副本数。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <h2 style="color: #3771e3;">Scaling overview</h2> -->
<h2 style="color: #3771e3;">扩缩概述</h2>
</div>
</div>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-8">
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item carousel-item active">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling1.svg">
</div>
<div class="item carousel-item">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling2.svg">
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="sr-only ">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <p>Scaling out a Deployment will ensure new Pods are created and scheduled to Nodes with available resources. Scaling in will reduce the number of Pods to the new desired state. Kubernetes also supports
<a href="/docs/user-guide/horizontal-pod-autoscaling/">autoscaling</a> of Pods, but it is outside of the scope of this tutorial. Scaling to zero is also possible, and it will terminate all Pods of the specified Deployment.</p> -->
<p>扩展 Deployment 将创建新的 Pods,并将资源调度请求分配到有可用资源的节点上,收缩 会将 Pods 数量减少至所需的状态。Kubernetes 还支持 Pods 的<a href="/zh/docs/tasks/run-application/horizontal-pod-autoscale/">自动缩放</a>,但这并不在本教程的讨论范围内。将 Pods 数量收缩到0也是可以的,但这会终止 Deployment 上所有已经部署的 Pods。</p>
<!-- <p>Running multiple instances of an application will require a way to distribute the traffic to all of them. Services have an integrated load-balancer that will distribute network traffic to all Pods of an exposed Deployment.
Services will monitor continuously the running Pods using endpoints, to ensure the traffic is sent only to available Pods.</p> -->
<p>运行应用程序的多个实例需要在它们之间分配流量。服务 (Service)有一种负载均衡器类型,可以将网络流量均衡分配到外部可访问的 Pods 上。服务将会一直通过端点来监视 Pods 的运行,保证流量只分配到可用的 Pods 上。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!-- <p><i>Scaling is accomplished by changing the number of replicas in a Deployment.</i></p> -->
<p><i>扩缩是通过改变 Deployment 中的副本数量来实现的。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!-- <p> Once you have multiple instances of an Application running, you would be able to do Rolling updates without downtime. We'll cover that in the next module. Now, let's go to the online terminal and scale our application.</p> -->
<p>一旦有了多个应用实例,就可以没有宕机地滚动更新。我们将会在下面的模块中介绍这些。现在让我们使用在线终端来体验一下应用程序的扩缩过程。</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<!-- <a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/scale/scale-interactive/" role="button">Start Interactive Tutorial <span class="btn__next"></span></a> -->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/scale/scale-interactive/" role="button">开始互动教程 <span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,4 @@
---
title: 更新你的应用
weight: 60
---
@@ -0,0 +1,43 @@
---
title: 交互式教程 - 更新你的应用
weight: 20
---
<!--
---
title: Interactive Tutorial - Updating Your App
weight: 20
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="/docs/tutorials/kubernetes-basics/public/css/overrides.css" rel="stylesheet">
<script src="https://katacoda.com/embed.js"></script>
<div class="layout" id="top">
<main class="content katacoda-content">
<div class="katacoda">
<div class="katacoda__alert">
要与终端交互,请使用桌面/平板电脑版本
</div>
<div class="katacoda__box" id="inline-terminal-1" data-katacoda-id="kubernetes-bootcamp/6" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/" role="button">回到 Kubernetes 的基础<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,190 @@
---
title: 执行滚动更新
weight: 10
---
<!--
---
title: Performing a Rolling Update
weight: 10
---
-->
<!DOCTYPE html>
<html lang="zh">
<body>
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab:300,400,700" rel="stylesheet">
<div class="layout" id="top">
<main class="content">
<div class="row">
<div class="col-md-8">
<h3>Objectives</h3>
<ul>
<!--
<li>Perform a rolling update using kubectl.</li>
-->
<li>使用 kubectl 执行滚动更新。</li>
</ul>
</div>
<div class="col-md-8">
<!--
<h3>Updating an application</h3>
-->
<h3>更新应用程序</h3>
<!--
<p>Users expect applications to be available all the time and developers are expected to deploy new versions of them several times a day. In Kubernetes this is done with rolling updates. <b>Rolling updates</b> allow Deployments' update to take place with zero downtime by incrementally updating Pods instances with new ones. The new Pods will be scheduled on Nodes with available resources.</p>
-->
<p>用户希望应用程序始终可用,而开发人员则需要每天多次部署它们的新版本。在 Kubernetes 中,这些是通过滚动更新(Rolling Updates)完成的。 <b>滚动更新</b> 允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。新的 Pod 将在具有可用资源的节点上进行调度。</p>
<!--
<p>In the previous module we scaled our application to run multiple instances. This is a requirement for performing updates without affecting application availability. By default, the maximum number of Pods that can be unavailable during the update and the maximum number of new Pods that can be created, is one. Both options can be configured to either numbers or percentages (of Pods).
In Kubernetes, updates are versioned and any Deployment update can be reverted to previous (stable) version.</p>
-->
<p>在前面的模块中,我们将应用程序扩展为运行多个实例。这是在不影响应用程序可用性的情况下执行更新的要求。默认情况下,更新期间不可用的 pod 的最大值和可以创建的新 pod 数都是 1。这两个选项都可以配置为(pod)数字或百分比。
在 Kubernetes 中,更新是经过版本控制的,任何 Deployment 更新都可以恢复到以前的(稳定)版本。</p>
</div>
<div class="col-md-4">
<div class="content__box content__box_lined">
<!--
<h3>Summary:</h3>
-->
<h3>摘要:</h3>
<ul>
<!--
<li>Updating an app</li>
-->
<li>更新应用</li>
</ul>
</div>
<div class="content__box content__box_fill">
<!--
<p><i>Rolling updates allow Deployments' update to take place with zero downtime by incrementally updating Pods instances with new ones. </i></p>
-->
<p><i>滚动更新允许通过使用新的实例逐步更新 Pod 实例从而实现 Deployments 更新,停机时间为零。</i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<h2 style="color: #3771e3;">Rolling updates overview</h2>
-->
<h2 style="color: #3771e3;">滚动更新概述</h2>
</div>
</div>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-8">
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
<li data-target="#myCarousel" data-slide-to="3"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item carousel-item active">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates1.svg" >
</div>
<div class="item carousel-item">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates2.svg">
</div>
<div class="item carousel-item">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates3.svg">
</div>
<div class="item carousel-item">
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates4.svg">
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="sr-only ">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<p>Similar to application Scaling, if a Deployment is exposed publicly, the Service will load-balance the traffic only to available Pods during the update. An available Pod is an instance that is available to the users of the application.</p>
-->
<p>与应用程序扩展类似,如果公开了 Deployment,服务将在更新期间仅对可用的 pod 进行负载均衡。可用 Pod 是应用程序用户可用的实例。</p>
<!--
<p>Rolling updates allow the following actions:</p>
-->
<p>滚动更新允许以下操作:</p>
<ul>
<!--
<li>Promote an application from one environment to another (via container image updates)</li>
<li>Rollback to previous versions</li>
<li>Continuous Integration and Continuous Delivery of applications with zero downtime</li>
-->
<li>将应用程序从一个环境提升到另一个环境(通过容器镜像更新)</li>
<li>回滚到以前的版本</li>
<li>持续集成和持续交付应用程序,无需停机</li>
</ul>
</div>
<div class="col-md-4">
<div class="content__box content__box_fill">
<!--
<p><i>If a Deployment is exposed publicly, the Service will load-balance the traffic only to available Pods during the update. </i></p>
-->
<p><i>如果 Deployment 是公开的,则服务将仅在更新期间对可用的 pod 进行负载均衡。 </i></p>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-8">
<!--
<p> In the following interactive tutorial, we'll update our application to a new version, and also perform a rollback.</p>
-->
<p> 在下面的交互式教程中,我们将应用程序更新为新版本,并执行回滚。</p>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<!--
<a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/update/update-interactive/" role="button">Start Interactive Tutorial <span class="btn__next"></span></a>
-->
<a class="btn btn-lg btn-success" href="/zh/docs/tutorials/kubernetes-basics/update/update-interactive/" role="button">启动交互教程<span class="btn__next"></span></a>
</div>
</div>
</main>
</div>
</body>
</html>
@@ -0,0 +1,5 @@
---
title: "安全"
weight: 40
---
@@ -0,0 +1,692 @@
---
title: 使用 AppArmor 限制容器对资源的访问
content_type: tutorial
weight: 10
---
<!--
title: Restrict a Container's Access to Resources with AppArmor
content_type: tutorial
weight: 10
-->
<!-- overview -->
{{< feature-state for_k8s_version="v1.4" state="beta" >}}
<!--
AppArmor is a Linux kernel security module that supplements the standard Linux user and group based
permissions to confine programs to a limited set of resources. AppArmor can be configured for any
application to reduce its potential attack surface and provide greater in-depth defense. It is
configured through profiles tuned to allow the access needed by a specific program or container,
such as Linux capabilities, network access, file permissions, etc. Each profile can be run in either
*enforcing* mode, which blocks access to disallowed resources, or *complain* mode, which only reports
violations.
-->
AppArmor 是一个 Linux 内核安全模块,
它补充了基于标准 Linux 用户和组的权限,将程序限制在一组有限的资源中。
AppArmor 可以配置为任何应用程序减少潜在的攻击面,并且提供更加深入的防御。
它通过调整配置文件进行配置,以允许特定程序或容器所需的访问,
如 Linux 权能字、网络访问、文件权限等。
每个配置文件都可以在
*强制(enforcing* 模式(阻止访问不允许的资源)或
*投诉(complain* 模式(仅报告冲突)下运行。
<!--
AppArmor can help you to run a more secure deployment by restricting what containers are allowed to
do, and/or provide better auditing through system logs. However, it is important to keep in mind
that AppArmor is not a silver bullet and can only do so much to protect against exploits in your
application code. It is important to provide good, restrictive profiles, and harden your
applications and cluster from other angles as well.
-->
AppArmor 可以通过限制允许容器执行的操作,
和/或通过系统日志提供更好的审计来帮助你运行更安全的部署。
但是,重要的是要记住 AppArmor 不是灵丹妙药,
只能做部分事情来防止应用程序代码中的漏洞。
提供良好的限制性配置文件,并从其他角度强化你的应用程序和集群非常重要。
## {{% heading "objectives" %}}
<!--
* See an example of how to load a profile on a node
* Learn how to enforce the profile on a Pod
* Learn how to check that the profile is loaded
* See what happens when a profile is violated
* See what happens when a profile cannot be loaded
-->
* 查看如何在节点上加载配置文件示例
* 了解如何在 Pod 上强制执行配置文件
* 了解如何检查配置文件是否已加载
* 查看违反配置文件时会发生什么
* 查看无法加载配置文件时会发生什么
## {{% heading "prerequisites" %}}
<!-- Make sure: -->
确保:
<!--
1. Kubernetes version is at least v1.4 -- Kubernetes support for AppArmor was added in
v1.4. Kubernetes components older than v1.4 are not aware of the new AppArmor annotations, and
will **silently ignore** any AppArmor settings that are provided. To ensure that your Pods are
receiving the expected protections, it is important to verify the Kubelet version of your nodes:
```shell
kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
```
```
gke-test-default-pool-239f5d02-gyn2: v1.4.0
gke-test-default-pool-239f5d02-x1kf: v1.4.0
gke-test-default-pool-239f5d02-xwux: v1.4.0
```
-->
1. Kubernetes 版本至少是 v1.4 —— AppArmor 在 Kubernetes v1.4 版本中才添加了对 AppArmor 的支持。
早于 v1.4 版本的 Kubernetes 组件不知道新的 AppArmor 注解
并且将会 **默认忽略** 提供的任何 AppArmor 设置。
为了确保你的 Pod 能够得到预期的保护,必须验证节点的 Kubelet 版本:
```shell
kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
```
```
gke-test-default-pool-239f5d02-gyn2: v1.4.0
gke-test-default-pool-239f5d02-x1kf: v1.4.0
gke-test-default-pool-239f5d02-xwux: v1.4.0
```
<!--
2. AppArmor kernel module is enabled -- For the Linux kernel to enforce an AppArmor profile, the
AppArmor kernel module must be installed and enabled. Several distributions enable the module by
default, such as Ubuntu and SUSE, and many others provide optional support. To check whether the
module is enabled, check the `/sys/module/apparmor/parameters/enabled` file:
```shell
cat /sys/module/apparmor/parameters/enabled
Y
```
If the Kubelet contains AppArmor support (>= v1.4), it will refuse to run a Pod with AppArmor
options if the kernel module is not enabled.
{{< note >}}
Ubuntu carries many AppArmor patches that have not been merged into the upstream Linux
kernel, including patches that add additional hooks and features. Kubernetes has only been
tested with the upstream version, and does not promise support for other features.
{{< /note >}}
-->
2. AppArmor 内核模块已启用 —— 要使 Linux 内核强制执行 AppArmor 配置文件,
必须安装并且启动 AppArmor 内核模块。默认情况下,有几个发行版支持该模块,
如 Ubuntu 和 SUSE,还有许多发行版提供可选支持。要检查模块是否已启用,请检查
`/sys/module/apparmor/parameters/enabled` 文件:
```shell
cat /sys/module/apparmor/parameters/enabled
Y
```
如果 Kubelet 包含 AppArmor 支持(>= v1.4),
但是内核模块未启用,它将拒绝运行带有 AppArmor 选项的 Pod。
{{< note >}}
Ubuntu 携带了许多没有合并到上游 Linux 内核中的 AppArmor 补丁,
包括添加附加钩子和特性的补丁。Kubernetes 只在上游版本中测试过,不承诺支持其他特性。
{{< /note >}}
<!--
3. Container runtime supports AppArmor -- Currently all common Kubernetes-supported container
runtimes should support AppArmor, like {{< glossary_tooltip term_id="docker">}},
{{< glossary_tooltip term_id="cri-o" >}} or {{< glossary_tooltip term_id="containerd" >}}.
Please refer to the corresponding runtime documentation and verify that the cluster fulfills
the requirements to use AppArmor.
-->
3. 容器运行时支持 AppArmor —— 目前所有常见的 Kubernetes 支持的容器运行时都应该支持 AppArmor,
像 {{< glossary_tooltip term_id="docker">}}{{< glossary_tooltip term_id="cri-o" >}}
或 {{< glossary_tooltip term_id="containerd" >}}。
请参考相应的运行时文档并验证集群是否满足使用 AppArmor 的要求。
<!--
4. Profile is loaded -- AppArmor is applied to a Pod by specifying an AppArmor profile that each
container should be run with. If any of the specified profiles is not already loaded in the
kernel, the Kubelet (>= v1.4) will reject the Pod. You can view which profiles are loaded on a
node by checking the `/sys/kernel/security/apparmor/profiles` file. For example:
```shell
ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
```
```
apparmor-test-deny-write (enforce)
apparmor-test-audit-write (enforce)
docker-default (enforce)
k8s-nginx (enforce)
```
For more details on loading profiles on nodes, see
[Setting up nodes with profiles](#setting-up-nodes-with-profiles).
-->
4. 配置文件已加载 —— 通过指定每个容器都应使用的 AppArmor 配置文件,
AppArmor 会被应用到 Pod 上。如果指定的任何配置文件尚未加载到内核,
Kubelet>= v1.4 将拒绝 Pod。
通过检查 `/sys/kernel/security/apparmor/profiles` 文件,
可以查看节点加载了哪些配置文件。例如:
```shell
ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
```
```
apparmor-test-deny-write (enforce)
apparmor-test-audit-write (enforce)
docker-default (enforce)
k8s-nginx (enforce)
```
有关在节点上加载配置文件的详细信息,请参见[使用配置文件设置节点](#setting-up-nodes-with-profiles)。
<!--
As long as the Kubelet version includes AppArmor support (>= v1.4), the Kubelet will reject a Pod
with AppArmor options if any of the prerequisites are not met. You can also verify AppArmor support
on nodes by checking the node ready condition message (though this is likely to be removed in a
later release):
-->
只要 Kubelet 版本包含 AppArmor 支持(>=v1.4)
如果不满足这些先决条件,Kubelet 将拒绝带有 AppArmor 选项的 Pod。
你还可以通过检查节点就绪状况消息来验证节点上的 AppArmor 支持(尽管这可能会在以后的版本中删除):
```shell
kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason=="KubeletReady")].message}\n{end}'
```
```
gke-test-default-pool-239f5d02-gyn2: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-x1kf: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-xwux: kubelet is posting ready status. AppArmor enabled
```
<!-- lessoncontent -->
<!-- ## Securing a Pod -->
## 保护 Pod {#securing-a-pod}
{{< note >}}
<!--
AppArmor is currently in beta, so options are specified as annotations. Once support graduates to
general availability, the annotations will be replaced with first-class fields (more details in
[Upgrade path to GA](#upgrade-path-to-general-availability)).
-->
AppArmor 目前处于 Beta 阶段,因此选项以注解形式设定。
一旦 AppArmor 支持进入正式发布阶段,注解将被替换为一阶的资源字段
(更多详情参见[升级到 GA 的途径](#upgrade-path-to-general-availability))。
{{< /note >}}
<!--
AppArmor profiles are specified *per-container*. To specify the AppArmor profile to run a Pod
container with, add an annotation to the Pod's metadata:
-->
AppArmor 配置文件是按 *逐个容器* 的形式来设置的。
要指定用来运行 Pod 容器的 AppArmor 配置文件,请向 Pod 的 metadata 添加注解:
```yaml
container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>
```
<!--
Where `<container_name>` is the name of the container to apply the profile to, and `<profile_ref>`
specifies the profile to apply. The `profile_ref` can be one of:
-->
`<container_name>` 的名称是配置文件所针对的容器的名称,`<profile_def>` 则设置要应用的配置文件。
`<profile_ref>` 可以是以下取值之一:
<!--
* `runtime/default` to apply the runtime's default profile
* `localhost/<profile_name>` to apply the profile loaded on the host with the name `<profile_name>`
* `unconfined` to indicate that no profiles will be loaded
-->
* `runtime/default` 应用运行时的默认配置
* `localhost/<profile_name>` 应用在主机上加载的名为 `<profile_name>` 的配置文件
* `unconfined` 表示不加载配置文件
<!--
See the [API Reference](#api-reference) for the full details on the annotation and profile name formats.
-->
有关注解和配置文件名称格式的详细信息,请参阅[API 参考](#api-reference)。
<!--
Kubernetes AppArmor enforcement works by first checking that all the prerequisites have been
met, and then forwarding the profile selection to the container runtime for enforcement. If the
prerequisites have not been met, the Pod will be rejected, and will not run.
-->
Kubernetes AppArmor 强制执行机制首先检查所有先决条件都已满足,
然后将所选的配置文件转发到容器运行时进行强制执行。
如果未满足先决条件,Pod 将被拒绝,并且不会运行。
<!--
To verify that the profile was applied, you can look for the AppArmor security option listed in the container created event:
-->
要验证是否应用了配置文件,可以在容器创建事件中查找所列出的 AppArmor 安全选项:
```shell
kubectl get events | grep Created
```
```
22s 22s 1 hello-apparmor Pod spec.containers{hello} Normal Created {kubelet e2e-test-stclair-node-pool-31nt} Created container with docker id 269a53b202d3; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
```
<!--
You can also verify directly that the container's root process is running with the correct profile by checking its proc attr:
-->
你还可以通过检查容器的 proc attr,直接验证容器的根进程是否以正确的配置文件运行:
```shell
kubectl exec <pod_name> cat /proc/1/attr/current
```
```
k8s-apparmor-example-deny-write (enforce)
```
<!-- ## Example -->
## 举例 {#example}
<!-- *This example assumes you have already set up a cluster with AppArmor support.* -->
*本例假设你已经设置了一个集群使用 AppArmor 支持。*
<!--
First, we need to load the profile we want to use onto our nodes. This profile denies all file writes:
-->
首先,我们需要将要使用的配置文件加载到节点上。配置文件拒绝所有文件写入:
```shell
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
```
<!--
Since we don't know where the Pod will be scheduled, we'll need to load the profile on all our
nodes. For this example we'll use SSH to install the profiles, but other approaches are
discussed in [Setting up nodes with profiles](#setting-up-nodes-with-profiles).
-->
由于我们不知道 Pod 将被调度到哪里,我们需要在所有节点上加载配置文件。
在本例中,我们将使用 SSH 来安装概要文件,
但是在[使用配置文件设置节点](#setting-up-nodes-with-profiles)中讨论了其他方法。
```shell
NODES=(
# The SSH-accessible domain names of your nodes
gke-test-default-pool-239f5d02-gyn2.us-central1-a.my-k8s
gke-test-default-pool-239f5d02-x1kf.us-central1-a.my-k8s
gke-test-default-pool-239f5d02-xwux.us-central1-a.my-k8s)
for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
EOF'
done
```
<!-- Next, we'll run a simple "Hello AppArmor" pod with the deny-write profile: -->
接下来,我们将运行一个带有拒绝写入配置文件的简单 “Hello AppArmor” Pod
{{< codenew file="pods/security/hello-apparmor.yaml" >}}
```shell
kubectl create -f ./hello-apparmor.yaml
```
<!--
If we look at the pod events, we can see that the Pod container was created with the AppArmor
profile "k8s-apparmor-example-deny-write":
-->
如果我们查看 Pod 事件,我们可以看到 Pod 容器是用 AppArmor
配置文件 “k8s-apparmor-example-deny-write” 所创建的:
```shell
kubectl get events | grep hello-apparmor
```
```
14s 14s 1 hello-apparmor Pod Normal Scheduled {default-scheduler } Successfully assigned hello-apparmor to gke-test-default-pool-239f5d02-gyn2
14s 14s 1 hello-apparmor Pod spec.containers{hello} Normal Pulling {kubelet gke-test-default-pool-239f5d02-gyn2} pulling image "busybox"
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Pulled {kubelet gke-test-default-pool-239f5d02-gyn2} Successfully pulled image "busybox"
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Created {kubelet gke-test-default-pool-239f5d02-gyn2} Created container with docker id 06b6cd1c0989; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
13s 13s 1 hello-apparmor Pod spec.containers{hello} Normal Started {kubelet gke-test-default-pool-239f5d02-gyn2} Started container with docker id 06b6cd1c0989
```
<!-- We can verify that the container is actually running with that profile by checking its proc attr: -->
我们可以通过检查该配置文件的 proc attr 来验证容器是否实际使用该配置文件运行:
```shell
kubectl exec hello-apparmor -- cat /proc/1/attr/current
```
```
k8s-apparmor-example-deny-write (enforce)
```
<!-- Finally, we can see what happens if we try to violate the profile by writing to a file: -->
最后,我们可以看到,如果我们尝试通过写入文件来违反配置文件会发生什么:
```shell
kubectl exec hello-apparmor -- touch /tmp/test
```
```
touch: /tmp/test: Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1
```
<!-- To wrap up, let's look at what happens if we try to specify a profile that hasn't been loaded: -->
最后,让我们看看如果我们试图指定一个尚未加载的配置文件会发生什么:
```shell
kubectl create -f /dev/stdin <<EOF
```
```yaml
apiVersion: v1
kind: Pod
metadata:
name: hello-apparmor-2
annotations:
container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-allow-write
spec:
containers:
- name: hello
image: busybox:1.28
command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
EOF
pod/hello-apparmor-2 created
```
```shell
kubectl describe pod hello-apparmor-2
```
```
Name: hello-apparmor-2
Namespace: default
Node: gke-test-default-pool-239f5d02-x1kf/
Start Time: Tue, 30 Aug 2016 17:58:56 -0700
Labels: <none>
Annotations: container.apparmor.security.beta.kubernetes.io/hello=localhost/k8s-apparmor-example-allow-write
Status: Pending
Reason: AppArmor
Message: Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
IP:
Controllers: <none>
Containers:
hello:
Container ID:
Image: busybox
Image ID:
Port:
Command:
sh
-c
echo 'Hello AppArmor!' && sleep 1h
State: Waiting
Reason: Blocked
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-dnz7v (ro)
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-dnz7v:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-dnz7v
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
23s 23s 1 {default-scheduler } Normal Scheduled Successfully assigned hello-apparmor-2 to e2e-test-stclair-node-pool-t1f5
23s 23s 1 {kubelet e2e-test-stclair-node-pool-t1f5} Warning AppArmor Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
```
<!--
Note the pod status is Pending, with a helpful error message: `Pod Cannot enforce AppArmor: profile
"k8s-apparmor-example-allow-write" is not loaded`. An event was also recorded with the same message.
-->
注意 Pod 呈现 Pending 状态,并且显示一条有用的错误信息:
`Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded`。
还用相同的消息记录了一个事件。
<!-- ## Administration -->
## 管理 {#administration}
<!-- ### Setting up nodes with profiles -->
### 使用配置文件设置节点 {#setting-up-nodes-with-profiles}
<!--
Kubernetes does not currently provide any native mechanisms for loading AppArmor profiles onto
nodes. There are lots of ways to setup the profiles though, such as:
-->
Kubernetes 目前不提供任何本地机制来将 AppArmor 配置文件加载到节点上。
有很多方法可以设置配置文件,例如:
<!--
* Through a [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) that runs a Pod on each node to
ensure the correct profiles are loaded. An example implementation can be found
[here](https://git.k8s.io/kubernetes/test/images/apparmor-loader).
* At node initialization time, using your node initialization scripts (e.g. Salt, Ansible, etc.) or
image.
* By copying the profiles to each node and loading them through SSH, as demonstrated in the
[Example](#example).
-->
* 通过在每个节点上运行 Pod 的
[DaemonSet](/zh/docs/concepts/workloads/controllers/daemonset/)来确保加载了正确的配置文件。
可以在[这里](https://git.k8s.io/kubernetes/test/images/apparmor-loader)找到实现示例。
* 在节点初始化时,使用节点初始化脚本(例如 Salt、Ansible 等)或镜像。
* 通过将配置文件复制到每个节点并通过 SSH 加载它们,如[示例](#example)。
<!--
The scheduler is not aware of which profiles are loaded onto which node, so the full set of profiles
must be loaded onto every node. An alternative approach is to add a node label for each profile (or
class of profiles) on the node, and use a
[node selector](/docs/concepts/configuration/assign-pod-node/) to ensure the Pod is run on a
node with the required profile.
-->
调度程序不知道哪些配置文件加载到哪个节点上,因此必须将全套配置文件加载到每个节点上。
另一种方法是为节点上的每个配置文件(或配置文件类)添加节点标签,
并使用[节点选择器](/zh/docs/concepts/configuration/assign-pod-node/)确保
Pod 在具有所需配置文件的节点上运行。
<!-- ### Restricting profiles with the PodSecurityPolicy -->
### 使用 PodSecurityPolicy 限制配置文件 {#restricting-profiles-with-the-podsecuritypolicy}
{{< note >}}
<!--
PodSecurityPolicy is deprecated in Kubernetes v1.21, and will be removed in v1.25.
See [PodSecurityPolicy](/docs/concepts/security/pod-security-policy/) documentation for more information.
-->
PodSecurityPolicy 在 Kubernetes v1.21 版本中已被废弃,将在 v1.25 版本移除。
查看 [PodSecurityPolicy](/zh/docs/concepts/security/pod-security-policy/) 文档获取更多信息。
{{< /note >}}
<!--
If the PodSecurityPolicy extension is enabled, cluster-wide AppArmor restrictions can be applied. To
enable the PodSecurityPolicy, the following flag must be set on the `apiserver`:
-->
如果启用了 PodSecurityPolicy 扩展,则可以应用集群范围的 AppArmor 限制。
要启用 PodSecurityPolicy,必须在 `apiserver` 上设置以下标志:
```
--enable-admission-plugins=PodSecurityPolicy[,others...]
```
<!-- The AppArmor options can be specified as annotations on the PodSecurityPolicy: -->
AppArmor 选项可以指定为 PodSecurityPolicy 上的注解:
```yaml
apparmor.security.beta.kubernetes.io/defaultProfileName: <profile_ref>
apparmor.security.beta.kubernetes.io/allowedProfileNames: <profile_ref>[,others...]
```
<!--
The default profile name option specifies the profile to apply to containers by default when none is
specified. The allowed profile names option specifies a list of profiles that Pod containers are
allowed to be run with. If both options are provided, the default must be allowed. The profiles are
specified in the same format as on containers. See the [API Reference](#api-reference) for the full
specification.
-->
默认配置文件名选项指定默认情况下在未指定任何配置文件时应用于容器的配置文件。
所允许的配置文件名称选项指定允许 Pod 容器运行期间所对应的配置文件列表。
如果同时提供了这两个选项,则必须允许默认值。
配置文件的指定格式与容器上的相同。有关完整规范,请参阅 [API 参考](#api-reference)。
<!-- ### Disabling AppArmor -->
### 禁用 AppArmor {#disabling-apparmor}
<!-- If you do not want AppArmor to be available on your cluster, it can be disabled by a command-line flag: -->
如果你不希望 AppArmor 在集群上可用,可以通过命令行标志禁用它:
```
--feature-gates=AppArmor=false
```
<!--
When disabled, any Pod that includes an AppArmor profile will fail validation with a "Forbidden"
error.
-->
禁用时,任何包含 AppArmor 配置文件的 Pod 都将导致验证失败,且返回 “Forbidden” 错误。
{{<note>}}
<!--
Even if the Kubernetes feature is disabled, runtimes may still enforce the default profile. The
option to disable the AppArmor feature will be removed when AppArmor graduates to general
availability (GA).
-->
即使此 Kubernetes 特性被禁用,运行时仍可能强制执行默认配置文件。
当 AppArmor 升级为正式版 (GA) 时,禁用 AppArmor 功能的选项将被删除。
{{</note>}}
<!-- ## Authoring Profiles -->
## 编写配置文件 {#authoring-profiles}
<!--
Getting AppArmor profiles specified correctly can be a tricky business. Fortunately there are some
tools to help with that:
-->
获得正确指定的 AppArmor 配置文件可能是一件棘手的事情。幸运的是,有一些工具可以帮助你做到这一点:
<!--
* `aa-genprof` and `aa-logprof` generate profile rules by monitoring an application's activity and
logs, and admitting the actions it takes. Further instructions are provided by the
[AppArmor documentation](https://gitlab.com/apparmor/apparmor/wikis/Profiling_with_tools).
* [bane](https://github.com/jfrazelle/bane) is an AppArmor profile generator for Docker that uses a
simplified profile language.
-->
* `aa-genprof` 和 `aa-logprof`
通过监视应用程序的活动和日志并准许它所执行的操作来生成配置文件规则。
[AppArmor 文档](https://gitlab.com/apparmor/apparmor/wikis/Profiling_with_tools)提供了进一步的指导。
* [bane](https://github.com/jfrazelle/bane)
是一个用于 Docker的 AppArmor 配置文件生成器,它使用一种简化的画像语言(profile language
<!--
To debug problems with AppArmor, you can check the system logs to see what, specifically, was
denied. AppArmor logs verbose messages to `dmesg`, and errors can usually be found in the system
logs or through `journalctl`. More information is provided in
[AppArmor failures](https://gitlab.com/apparmor/apparmor/wikis/AppArmor_Failures).
-->
想要调试 AppArmor 的问题,你可以检查系统日志,查看具体拒绝了什么。
AppArmor 将详细消息记录到 `dmesg`
错误通常可以在系统日志中或通过 `journalctl` 找到。
更多详细信息见 [AppArmor 失败](https://gitlab.com/apparmor/apparmor/wikis/AppArmor_Failures)。
<!-- ## API Reference -->
## API 参考 {#api-reference}
<!-- ### Pod Annotation -->
### Pod 注解 {#pod-annotation}
<!-- Specifying the profile a container will run with: -->
指定容器将使用的配置文件:
<!--
- **key**: `container.apparmor.security.beta.kubernetes.io/<container_name>`
Where `<container_name>` matches the name of a container in the Pod.
A separate profile can be specified for each container in the Pod.
- **value**: a profile reference, described below
-->
- **键名**: `container.apparmor.security.beta.kubernetes.io/<container_name>`
,其中 `<container_name>` 与 Pod 中某容器的名称匹配。
可以为 Pod 中的每个容器指定单独的配置文件。
- **键值**: 对配置文件的引用,如下所述
<!-- ### Profile Reference -->
### 配置文件引用 {#profile-reference}
<!--
- `runtime/default`: Refers to the default runtime profile.
- Equivalent to not specifying a profile (without a PodSecurityPolicy default), except it still
requires AppArmor to be enabled.
- In practice, many container runtimes use the same OCI default profile, defined here:
https://github.com/containers/common/blob/main/pkg/apparmor/apparmor_linux_template.go
- `localhost/<profile_name>`: Refers to a profile loaded on the node (localhost) by name.
- The possible profile names are detailed in the
[core policy reference](https://gitlab.com/apparmor/apparmor/wikis/AppArmor_Core_Policy_Reference#profile-names-and-attachment-specifications).
- `unconfined`: This effectively disables AppArmor on the container.
-->
- `runtime/default`: 指默认运行时配置文件。
- 等同于不指定配置文件(没有 PodSecurityPolicy 默认值),只是它仍然需要启用 AppArmor。
- 实际上,许多容器运行时使用相同的 OCI 默认配置文件,在此处定义:
https://github.com/containers/common/blob/main/pkg/apparmor/apparmor_linux_template.go
- `localhost/<profile_name>`: 按名称引用加载到节点(localhost)上的配置文件。
- 可能的配置文件名在[核心策略参考](https://gitlab.com/apparmor/apparmor/wikis/AppArmor_Core_Policy_Reference#profile-names-and-attachment-specifications)。
- `unconfined`: 这相当于为容器禁用 AppArmor。
<!-- Any other profile reference format is invalid. -->
任何其他配置文件引用格式无效。
<!-- ### PodSecurityPolicy Annotations -->
### PodSecurityPolicy 注解 {#podsecuritypolicy-annotations}
<!-- Specifying the default profile to apply to containers when none is provided: -->
指定在未提供容器时应用于容器的默认配置文件:
<!--
* **key**: `apparmor.security.beta.kubernetes.io/defaultProfileName`
* **value**: a profile reference, described above
-->
* **键名**: `apparmor.security.beta.kubernetes.io/defaultProfileName`
* **键值**: 如上述文件参考所述
<!-- Specifying the list of profiles Pod containers is allowed to specify: -->
上面描述的指定配置文件,Pod 容器列表的配置文件引用允许指定:
<!--
* **key**: `apparmor.security.beta.kubernetes.io/allowedProfileNames`
* **value**: a comma-separated list of profile references (described above)
- Although an escaped comma is a legal character in a profile name, it cannot be explicitly
allowed here.
-->
* **键名**: `apparmor.security.beta.kubernetes.io/allowedProfileNames`
* **键值**: 配置文件引用的逗号分隔列表(如上所述)
- 尽管转义逗号是配置文件名中的合法字符,但此处不能显式允许。
## {{% heading "whatsnext" %}}
<!-- Additional resources: -->
其他资源:
<!--
* [Quick guide to the AppArmor profile language](https://gitlab.com/apparmor/apparmor/wikis/QuickProfileLanguage)
* [AppArmor core policy reference](https://gitlab.com/apparmor/apparmor/wikis/Policy_Layout)
-->
* [Apparmor 配置文件语言快速指南](https://gitlab.com/apparmor/apparmor/wikis/QuickProfileLanguage)
* [Apparmor 核心策略参考](https://gitlab.com/apparmor/apparmor/wikis/Policy_Layout)
@@ -0,0 +1,444 @@
---
title: 在集群级别应用 Pod 安全标准
content_type: tutorial
weight: 10
---
<!--
title: Apply Pod Security Standards at the Cluster Level
content_type: tutorial
weight: 10
-->
{{% alert title="Note" %}}
<!-- This tutorial applies only for new clusters. -->
本教程仅适用于新集群。
{{% /alert %}}
<!--
Pod Security admission (PSA) is enabled by default in v1.23 and later, as it has
[graduated to beta](/blog/2021/12/09/pod-security-admission-beta/).
Pod Security
is an admission controller that carries out checks against the Kubernetes
[Pod Security Standards](/docs/concepts/security/pod-security-standards/) when new pods are
created. This tutorial shows you how to enforce the `baseline` Pod Security
Standard at the cluster level which applies a standard configuration
to all namespaces in a cluster.
To apply Pod Security Standards to specific namespaces, refer to [Apply Pod Security Standards at the namespace level](/docs/tutorials/security/ns-level-pss).
-->
Pod 安全准入(PSA)在 v1.23 及更高版本默认启用,
因为它[升级到测试版(beta](/blog/2021/12/09/pod-security-admission-beta/)。
Pod 安全准入是在创建 Pod 时应用
[Pod 安全标准](/zh/docs/concepts/security/pod-security-standards/)的准入控制器。
本教程将向你展示如何在集群级别实施 `baseline` Pod 安全标准,
该标准将标准配置应用于集群中的所有名称空间。
要将 Pod 安全标准应用于特定名字空间,
请参阅[在名字空间级别应用 Pod 安全标准](/zh/docs/tutorials/security/ns-level-pss)。
## {{% heading "prerequisites" %}}
<!--
Install the following on your workstation:
- [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
-->
在你的工作站中安装以下内容:
- [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
<!--
## Choose the right Pod Security Standard to apply
[Pod Security Admission](/docs/concepts/security/pod-security-admission/)
lets you apply built-in [Pod Security Standards](/docs/concepts/security/pod-security-standards/)
with the following modes: `enforce`, `audit`, and `warn`.
To gather information that helps you to choose the Pod Security Standards
that are most appropriate for your configuration, do the following:
-->
## 正确选择要应用的 Pod 安全标准 {#choose-the-right-pod-security-standard-to-apply}
[Pod 安全准入](/zh/docs/concepts/security/pod-security-admission/)
允许你使用以下模式应用内置的
[Pod 安全标准](/zh/docs/concepts/security/pod-security-standards/):
`enforce``audit``warn`
要收集信息以便选择最适合你的配置的 Pod 安全标准,请执行以下操作:
<!--
1. Create a cluster with no Pod Security Standards applied:
-->
1. 创建一个没有应用 Pod 安全标准的集群:
```shell
kind create cluster --name psa-wo-cluster-pss --image kindest/node:v1.23.0
```
<!-- The output is similar to this: -->
输出类似于:
```
Creating cluster "psa-wo-cluster-pss" ...
✓ Ensuring node image (kindest/node:v1.23.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-psa-wo-cluster-pss"
You can now use your cluster with:
kubectl cluster-info --context kind-psa-wo-cluster-pss
Thanks for using kind! 😊
```
<!--
1. Set the kubectl context to the new cluster:
-->
2. 将 kubectl 上下文设置为新集群:
```shell
kubectl cluster-info --context kind-psa-wo-cluster-pss
```
<!-- The output is similar to this: -->
输出类似于:
```
Kubernetes control plane is running at https://127.0.0.1:61350
CoreDNS is running at https://127.0.0.1:61350/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```
<!--
1. Get a list of namespaces in the cluster:
-->
3. 获取集群中的名字空间列表:
```shell
kubectl get ns
```
<!-- The output is similar to this: -->
输出类似于:
```
NAME STATUS AGE
default Active 9m30s
kube-node-lease Active 9m32s
kube-public Active 9m32s
kube-system Active 9m32s
local-path-storage Active 9m26s
```
<!--
1. Use `--dry-run=server` to understand what happens when different Pod Security Standards
are applied:
-->
4. 使用 `--dry-run=server` 来了解应用不同的 Pod 安全标准时会发生什么:
1. Privileged
```shell
kubectl label --dry-run=server --overwrite ns --all \
pod-security.kubernetes.io/enforce=privileged
```
<!-- The output is similar to this: -->
输出类似于:
```
namespace/default labeled
namespace/kube-node-lease labeled
namespace/kube-public labeled
namespace/kube-system labeled
namespace/local-path-storage labeled
```
2. Baseline
```shell
kubectl label --dry-run=server --overwrite ns --all \
pod-security.kubernetes.io/enforce=baseline
```
<!-- The output is similar to this: -->
输出类似于:
```
namespace/default labeled
namespace/kube-node-lease labeled
namespace/kube-public labeled
Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "baseline:latest"
Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes
Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes
Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged
namespace/kube-system labeled
namespace/local-path-storage labeled
```
3. Restricted
```shell
kubectl label --dry-run=server --overwrite ns --all \
pod-security.kubernetes.io/enforce=restricted
```
<!-- The output is similar to this: -->
输出类似于:
```
namespace/default labeled
namespace/kube-node-lease labeled
namespace/kube-public labeled
Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "restricted:latest"
Warning: coredns-7bb9c7b568-hsptc (and 1 other pod): unrestricted capabilities, runAsNonRoot != true, seccompProfile
Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true
Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
namespace/kube-system labeled
Warning: existing pods in namespace "local-path-storage" violate the new PodSecurity enforce level "restricted:latest"
Warning: local-path-provisioner-d6d9f7ffc-lw9lh: allowPrivilegeEscalation != false, unrestricted capabilities, runAsNonRoot != true, seccompProfile
namespace/local-path-storage labeled
```
<!--
From the previous output, you'll notice that applying the `privileged` Pod Security Standard shows no warnings
for any namespaces. However, `baseline` and `restricted` standards both have
warnings, specifically in the `kube-system` namespace.
-->
从前面的输出中,你会注意到应用 `privileged` Pod 安全标准不会显示任何名字空间的警告。
然而,`baseline` 和 `restricted` 标准都有警告,特别是在 `kube-system` 名字空间中。
<!--
## Set modes, versions and standards
In this section, you apply the following Pod Security Standards to the `latest` version:
* `baseline` standard in `enforce` mode.
* `restricted` standard in `warn` and `audit` mode.
-->
## 设置模式、版本和标准 {#set-modes-versions-and-standards}
在本节中,你将以下 Pod 安全标准应用于最新(`latest`)版本:
* 在 `enforce` 模式下的 `baseline` 标准。
* `warn` 和 `audit` 模式下的 `restricted` 标准。
<!--
The `baseline` Pod Security Standard provides a convenient
middle ground that allows keeping the exemption list short and prevents known
privilege escalations.
Additionally, to prevent pods from failing in `kube-system`, you'll exempt the namespace
from having Pod Security Standards applied.
When you implement Pod Security Admission in your own environment, consider the
following:
-->
`baseline` Pod 安全标准提供了一个方便的中间立场,能够保持豁免列表简短并防止已知的特权升级。
此外,为了防止 `kube-system` 中的 Pod 失败,你将免除该名字空间应用 Pod 安全标准。
在你自己的环境中实施 Pod 安全准入时,请考虑以下事项:
<!--
1. Based on the risk posture applied to a cluster, a stricter Pod Security
Standard like `restricted` might be a better choice.
1. Exempting the `kube-system` namespace allows pods to run as
`privileged` in this namespace. For real world use, the Kubernetes project
strongly recommends that you apply strict RBAC
policies that limit access to `kube-system`, following the principle of least
privilege.
To implement the preceding standards, do the following:
1. Create a configuration file that can be consumed by the Pod Security
Admission Controller to implement these Pod Security Standards:
-->
1. 根据应用于集群的风险状况,更严格的 Pod 安全标准(如 `restricted`)可能是更好的选择。
2. 对 `kube-system` 名字空间进行赦免会允许 Pod 在其中以 `privileged` 模式运行。
对于实际使用,Kubernetes 项目强烈建议你应用严格的 RBAC 策略来限制对 `kube-system` 的访问,
遵循最小特权原则。
3. 创建一个配置文件,Pod 安全准入控制器可以使用该文件来实现这些 Pod 安全标准:
```
mkdir -p /tmp/pss
cat <<EOF > /tmp/pss/cluster-level-pss.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1beta1
kind: PodSecurityConfiguration
defaults:
enforce: "baseline"
enforce-version: "latest"
audit: "restricted"
audit-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
usernames: []
runtimeClasses: []
namespaces: [kube-system]
EOF
```
<!--
1. Configure the API server to consume this file during cluster creation:
-->
4. 在创建集群时配置 API 服务器使用此文件:
```
cat <<EOF > /tmp/pss/cluster-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
apiServer:
extraArgs:
admission-control-config-file: /etc/config/cluster-level-pss.yaml
extraVolumes:
- name: accf
hostPath: /etc/config
mountPath: /etc/config
readOnly: false
pathType: "DirectoryOrCreate"
extraMounts:
- hostPath: /tmp/pss
containerPath: /etc/config
# optional: if set, the mount is read-only.
# default false
readOnly: false
# optional: if set, the mount needs SELinux relabeling.
# default false
selinuxRelabel: false
# optional: set propagation mode (None, HostToContainer or Bidirectional)
# see https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation
# default None
propagation: None
EOF
```
{{<note>}}
<!--
If you use Docker Desktop with KinD on macOS, you can
add `/tmp` as a Shared Directory under the menu item
**Preferences > Resources > File Sharing**.
-->
如果你在 macOS 上使用 Docker Desktop 和 KinD
你可以在菜单项 **Preferences > Resources > File Sharing**
下添加 `/tmp` 作为共享目录。
{{</note>}}
<!--
1. Create a cluster that uses Pod Security Admission to apply
these Pod Security Standards:
-->
5. 创建一个使用 Pod 安全准入的集群来应用这些 Pod 安全标准:
```shell
kind create cluster --name psa-with-cluster-pss --image kindest/node:v1.23.0 --config /tmp/pss/cluster-config.yaml
```
<!-- The output is similar to this: -->
输出类似于:
```
Creating cluster "psa-with-cluster-pss" ...
✓ Ensuring node image (kindest/node:v1.23.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-psa-with-cluster-pss"
You can now use your cluster with:
kubectl cluster-info --context kind-psa-with-cluster-pss
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
```
<!--
1. Point kubectl to the cluster
-->
6. 将 kubectl 指向集群
```shell
kubectl cluster-info --context kind-psa-with-cluster-pss
```
<!-- The output is similar to this: -->
输出类似于:
```
Kubernetes control plane is running at https://127.0.0.1:63855
CoreDNS is running at https://127.0.0.1:63855/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```
<!--
1. Create the following Pod specification for a minimal configuration in the default namespace:
-->
7. 创建以下 Pod 规约作为在 default 名字空间中的一个最小配置:
```
cat <<EOF > /tmp/pss/nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
EOF
```
<!--
1. Create the Pod in the cluster:
-->
8. 在集群中创建 Pod
```shell
kubectl apply -f /tmp/pss/nginx-pod.yaml
```
<!-- The output is similar to this: -->
输出类似于:
```
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/nginx created
```
<!--
## Clean up
Run `kind delete cluster --name psa-with-cluster-pss` and
`kind delete cluster --name psa-wo-cluster-pss` to delete the clusters you
created.
-->
## 清理 {#clean-up}
运行 `kind delete cluster --name psa-with-cluster-pss` 和
`kind delete cluster --name psa-wo-cluster-pss` 来删除你创建的集群。
## {{% heading "whatsnext" %}}
<!--
- Run a
[shell script](/examples/security/kind-with-cluster-level-baseline-pod-security.sh)
to perform all the preceding steps at once:
1. Create a Pod Security Standards based cluster level Configuration
2. Create a file to let API server consumes this configuration
3. Create a cluster that creates an API server with this configuration
4. Set kubectl context to this new cluster
5. Create a minimal pod yaml file
6. Apply this file to create a Pod in the new cluster
- [Pod Security Admission](/docs/concepts/security/pod-security-admission/)
- [Pod Security Standards](/docs/concepts/security/pod-security-standards/)
- [Apply Pod Security Standards at the namespace level](/docs/tutorials/security/ns-level-pss/)
-->
- 运行一个 [shell 脚本](/zh/examples/security/kind-with-cluster-level-baseline-pod-security.sh)
一次执行前面的所有步骤:
1. 创建一个基于 Pod 安全标准的集群级别配置
2. 创建一个文件让 API 服务器消费这个配置
3. 创建一个集群,用这个配置创建一个 API 服务器
4. 设置 kubectl 上下文为这个新集群
5. 创建一个最小的 Pod yaml 文件
6. 应用这个文件,在新集群中创建一个 Pod
- [Pod 安全准入](/zh/docs/concepts/security/pod-security-admission/)
- [Pod 安全标准](/zh/docs/concepts/security/pod-security-standards/)
- [在名字空间级别应用 Pod 安全标准](/zh/docs/tutorials/security/ns-level-pss/)
@@ -0,0 +1,252 @@
---
title: 在名字空间级别应用 Pod 安全标准
content_type: tutorial
weight: 10
---
<!--
title: Apply Pod Security Standards at the Namespace Level
content_type: tutorial
weight: 10
-->
{{% alert title="Note" %}}
<!-- This tutorial applies only for new clusters. -->
本教程仅适用于新集群。
{{% /alert %}}
<!--
Pod Security admission (PSA) is enabled by default in v1.23 and later, as it
[graduated to beta](/blog/2021/12/09/pod-security-admission-beta/). Pod Security Admission
is an admission controller that applies
[Pod Security Standards](/docs/concepts/security/pod-security-standards/)
when pods are created. In this tutorial, you will enforce the `baseline` Pod Security Standard,
one namespace at a time.
You can also apply Pod Security Standards to multiple namespaces at once at the cluster
level. For instructions, refer to
[Apply Pod Security Standards at the cluster level](/docs/tutorials/security/cluster-level-pss).
-->
Pod 安全准入(PSA)在 v1.23 及更高版本默认启用,
因为它[升级到测试版(beta](/blog/2021/12/09/pod-security-admission-beta/)。
Pod 安全准入是在创建 Pod 时应用
[Pod 安全标准](/zh/docs/concepts/security/pod-security-standards/)的准入控制器。
在本教程中,你将应用 `baseline` Pod 安全标准,每次一个名字空间。
你还可以在集群级别一次将 Pod 安全标准应用于多个名称空间。
有关说明,请参阅[在集群级别应用 Pod 安全标准](/zh/docs/tutorials/security/cluster-level-pss)。
## {{% heading "prerequisites" %}}
<!--
Install the following on your workstation:
- [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
- [kubectl](/docs/tasks/tools/)
-->
在你的工作站中安装以下内容:
- [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
- [kubectl](/zh/docs/tasks/tools/)
<!--
## Create cluster
1. Create a `KinD` cluster as follows:
-->
## 创建集群 {#create-cluster}
2. 按照如下方式创建一个 `KinD` 集群:
```shell
kind create cluster --name psa-ns-level --image kindest/node:v1.23.0
```
<!-- The output is similar to this: -->
输出类似于:
```
Creating cluster "psa-ns-level" ...
✓ Ensuring node image (kindest/node:v1.23.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-psa-ns-level"
You can now use your cluster with:
kubectl cluster-info --context kind-psa-ns-level
Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/
```
<!-- 1. Set the kubectl context to the new cluster: -->
1. 将 kubectl 上下文设置为新集群:
```shell
kubectl cluster-info --context kind-psa-ns-level
```
<!-- The output is similar to this: -->
输出类似于:
```
Kubernetes control plane is running at https://127.0.0.1:50996
CoreDNS is running at https://127.0.0.1:50996/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```
<!--
## Create a namespace
Create a new namespace called `example`:
-->
## 创建名字空间 {#create-a-namespace}
创建一个名为 `example` 的新名字空间:
```shell
kubectl create ns example
```
<!-- The output is similar to this: -->
输出类似于:
```
namespace/example created
```
<!--
## Apply Pod Security Standards
1. Enable Pod Security Standards on this namespace using labels supported by
built-in Pod Security Admission. In this step we will warn on baseline pod
security standard as per the latest version (default value)
-->
## 应用 Pod 安全标准 {#apply-pod-security-standards}
1. 使用内置 Pod 安全准入所支持的标签在此名字空间上启用 Pod 安全标准。
在这一步中,我们将根据最新版本(默认值)对基线 Pod 安全标准发出警告。
```shell
kubectl label --overwrite ns example \
pod-security.kubernetes.io/warn=baseline \
pod-security.kubernetes.io/warn-version=latest
```
<!--
2. Multiple pod security standards can be enabled on any namespace, using labels.
Following command will `enforce` the `baseline` Pod Security Standard, but
`warn` and `audit` for `restricted` Pod Security Standards as per the latest
version (default value)
-->
2. 可以使用标签在任何名字空间上启用多个 Pod 安全标准。
以下命令将强制(`enforce` 执行基线(`baseline`Pod 安全标准,
但根据最新版本(默认值)对受限(`restricted`Pod 安全标准执行警告(`warn`)和审核(`audit`)。
```
kubectl label --overwrite ns example \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/warn-version=latest \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/audit-version=latest
```
<!--
## Verify the Pod Security Standards
1. Create a minimal pod in `example` namespace:
-->
## 验证 Pod 安全标准 {#verify-the-pod-security-standards}
1. 在 `example` 名字空间中创建一个最小的 pod:
```shell
cat <<EOF > /tmp/pss/nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
EOF
```
<!--
2. Apply the pod spec to the cluster in `example` namespace:
-->
1. 将 Pod 规约应用到集群中的 `example` 名字空间中:
```shell
kubectl apply -n example -f /tmp/pss/nginx-pod.yaml
```
<!-- The output is similar to this: -->
输出类似于:
```
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/nginx created
```
<!--
1. Apply the pod spec to the cluster in `default` namespace:
-->
3. 将 Pod 规约应用到集群中的 `default` 名字空间中:
```shell
kubectl apply -n default -f /tmp/pss/nginx-pod.yaml
```
<!-- Output is similar to this: -->
输出类似于:
```
pod/nginx created
```
<!--
The Pod Security Standards were applied only to the `example`
namespace. You could create the same Pod in the `default` namespace
with no warnings.
-->
以上 Pod 安全标准仅被应用到 `example` 名字空间。
你可以在没有警告的情况下在 `default` 名字空间中创建相同的 Pod。
<!--
## Clean up
Run `kind delete cluster -name psa-ns-level` to delete the cluster created.
-->
## 清理 {#clean-up}
运行 `kind delete cluster -name psa-ns-level` 删除创建的集群。
## {{% heading "whatsnext" %}}
<!--
- Run a
[shell script](/examples/security/kind-with-namespace-level-baseline-pod-security.sh)
to perform all the preceding steps all at once.
1. Create KinD cluster
2. Create new namespace
3. Apply `baseline` Pod Security Standard in `enforce` mode while applying
`restricted` Pod Security Standard also in `warn` and `audit` mode.
4. Create a new pod with the following pod security standards applied
- [Pod Security Admission](/docs/concepts/security/pod-security-admission/)
- [Pod Security Standards](/docs/concepts/security/pod-security-standards/)
- [Apply Pod Security Standards at the cluster level](/docs/tutorials/security/cluster-level-pss/)
-->
- 运行一个 [shell 脚本](/examples/security/kind-with-namespace-level-baseline-pod-security.sh)
一次执行所有前面的步骤。
1. 创建 KinD 集群
2. 创建新的名字空间
3. 在 `enforce` 模式下应用 `baseline` Pod 安全标准,
同时在 `warn` 和 `audit` 模式下应用 `restricted` Pod 安全标准。
4. 创建一个应用以下 Pod 安全标准的新 Pod
- [Pod 安全准入](/zh/docs/concepts/security/pod-security-admission/)
- [Pod 安全标准](/zh/docs/concepts/security/pod-security-standards/)
- [在集群级别应用 Pod 安全标准](/zh/docs/tutorials/security/cluster-level-pss/)
@@ -0,0 +1,783 @@
---
title: 使用 seccomp 限制容器的系统调用
content_type: tutorial
weight: 20
min-kubernetes-server-version: v1.22
---
<!--
reviewers:
- hasheddan
- pjbgf
- saschagrunert
title: Restrict a Container's Syscalls with seccomp
content_type: tutorial
weight: 20
min-kubernetes-server-version: v1.22
-->
<!-- overview -->
{{< feature-state for_k8s_version="v1.19" state="stable" >}}
<!--
Seccomp stands for secure computing mode and has been a feature of the Linux
kernel since version 2.6.12. It can be used to sandbox the privileges of a
process, restricting the calls it is able to make from userspace into the
kernel. Kubernetes lets you automatically apply seccomp profiles loaded onto a
{{< glossary_tooltip text="node" term_id="node" >}} to your Pods and containers.
Identifying the privileges required for your workloads can be difficult. In this
tutorial, you will go through how to load seccomp profiles into a local
Kubernetes cluster, how to apply them to a Pod, and how you can begin to craft
profiles that give only the necessary privileges to your container processes.
-->
Seccomp 代表安全计算(Secure Computing)模式,自 2.6.12 版本以来,一直是 Linux 内核的一个特性。
它可以用来沙箱化进程的权限,限制进程从用户态到内核态的调用。
Kubernetes 能使你自动将加载到 {{< glossary_tooltip text="节点" term_id="node" >}}上的
seccomp 配置文件应用到你的 Pod 和容器。
识别你的工作负载所需要的权限是很困难的。在本篇教程中,
你将了解如何将 seccomp 配置文件加载到本地的 Kubernetes 集群中,
如何将它们应用到 Pod,以及如何开始制作只为容器进程提供必要的权限的配置文件。
## {{% heading "objectives" %}}
<!--
* Learn how to load seccomp profiles on a node
* Learn how to apply a seccomp profile to a container
* Observe auditing of syscalls made by a container process
* Observe behavior when a missing profile is specified
* Observe a violation of a seccomp profile
* Learn how to create fine-grained seccomp profiles
* Learn how to apply a container runtime default seccomp profile
-->
* 了解如何在节点上加载 seccomp 配置文件
* 了解如何将 seccomp 配置文件应用到容器上
* 观察容器进程对系统调用的审计
* 观察指定的配置文件缺失时的行为
* 观察违反 seccomp 配置文件的行为
* 了解如何创建细粒度的 seccomp 配置文件
* 了解如何应用容器运行时所默认的 seccomp 配置文件
## {{% heading "prerequisites" %}}
<!--
In order to complete all steps in this tutorial, you must install
[kind](/docs/tasks/tools/#kind) and [kubectl](/docs/tasks/tools/#kubectl).
This tutorial shows some examples that are still alpha (since v1.22) and
others that use only generally available seccomp functionality. You should
make sure that your cluster is
[configured correctly](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)
for the version you are using.
The tutorial also uses the `curl` tool for downloading examples to your computer.
You can adapt the steps to use a different tool if you prefer.
-->
为了完成本篇教程中的所有步骤,你必须安装 [kind](/zh/docs/tasks/tools/#kind)
和 [kubectl](/zh/docs/tasks/tools/#kubectl)。
本篇教程演示的某些示例仍然是 alpha 状态(自 v1.22 起),另一些示例则仅使用 seccomp 正式发布的功能。
你应该确保,针对你使用的版本,
[正确配置](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)了集群。
本篇教程也使用了 `curl` 工具来下载示例到你的计算机上。
你可以使用其他自己偏好的工具来自适应这些步骤。
{{< note >}}
<!--
It is not possible to apply a seccomp profile to a container running with
`privileged: true` set in the container's `securityContext`. Privileged containers always
run as `Unconfined`.
-->
无法将 seccomp 配置文件应用于在容器的 `securityContext` 中设置了 `privileged: true` 的容器。
特权容器始终以 `Unconfined` 的方式运行。
{{< /note >}}
<!-- steps -->
<!--
## Download example seccomp profiles {#download-profiles}
The contents of these profiles will be explored later on, but for now go ahead
and download them into a directory named `profiles/` so that they can be loaded
into the cluster.
-->
## 下载示例 seccomp 配置文件 {#download-profiles}
这些配置文件的内容将在稍后进行分析,
现在先将它们下载到名为 `profiles/` 的目录中,以便将它们加载到集群中。
{{< tabs name="tab_with_code" >}}
{{{< tab name="audit.json" >}}
{{< codenew file="pods/security/seccomp/profiles/audit.json" >}}
{{< /tab >}}
{{< tab name="violation.json" >}}
{{< codenew file="pods/security/seccomp/profiles/violation.json" >}}
{{< /tab >}}}
{{< tab name="fine-grained.json" >}}
{{< codenew file="pods/security/seccomp/profiles/fine-grained.json" >}}
{{< /tab >}}}
{{< /tabs >}}
<!-- Run these commands: -->
执行这些命令:
```shell
mkdir ./profiles
curl -L -o profiles/audit.json https://k8s.io/examples/pods/security/seccomp/profiles/audit.json
curl -L -o profiles/violation.json https://k8s.io/examples/pods/security/seccomp/profiles/violation.json
curl -L -o profiles/fine-grained.json https://k8s.io/examples/pods/security/seccomp/profiles/fine-grained.json
ls profiles
```
<!-- You should see three profiles listed at the end of the final step: -->
你应该看到在最后一步的末尾列出有三个配置文件:
```
audit.json fine-grained.json violation.json
```
<!--
## Create a local Kubernetes cluster with kind
For simplicity, [kind](https://kind.sigs.k8s.io/) can be used to create a single
node cluster with the seccomp profiles loaded. Kind runs Kubernetes in Docker,
so each node of the cluster is a container. This allows for files
to be mounted in the filesystem of each container similar to loading files
onto a node.
-->
## 使用 kind 创建本地 Kubernetes 集群 {#create-a-local-kubernetes-cluster-with-kind}
为简单起见,[kind](https://kind.sigs.k8s.io/) 可用来创建加载了 seccomp 配置文件的单节点集群。
Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点都是一个容器。
这允许将文件挂载到每个容器的文件系统中,类似于将文件加载到节点上。
{{< codenew file="pods/security/seccomp/kind.yaml" >}}
<!--
Download that example kind configuration, and save it to a file named `kind.yaml`:
-->
下载该示例 kind 配置,并将其保存到名为 `kind.yaml` 的文件中:
```shell
curl -L -O https://k8s.io/examples/pods/security/seccomp/kind.yaml
```
<!--
You can set a specific Kubernetes version by setting the node's container image.
See [Nodes](https://kind.sigs.k8s.io/docs/user/configuration/#nodes) within the
kind documentation about configuration for more details on this.
This tutorial assumes you are using Kubernetes {{< param "version" >}}.
-->
你可以通过设置节点的容器镜像来设置特定的 Kubernetes 版本。
有关此类配置的更多信息,
参阅 kind 文档中[节点](https://kind.sigs.k8s.io/docs/user/configuration/#nodes)小节。
本篇教程假定你正在使用 Kubernetes {{< param "version" >}}。
<!--
As an alpha feature, you can configure Kubernetes to use the profile that the
{{< glossary_tooltip text="container runtime" term_id="container-runtime" >}}
prefers by default, rather than falling back to `Unconfined`.
If you want to try that, see
[enable the use of `RuntimeDefault` as the default seccomp profile for all workloads](#enable-the-use-of-runtimedefault-as-the-default-seccomp-profile-for-all-workloads)
before you continue.
-->
作为 alpha 特性,你可以将 Kubernetes 配置为使用
{{< glossary_tooltip text="容器运行时" term_id="container-runtime" >}}
默认首选的配置文件,而不是回退到 `Unconfined`
如果你想尝试,请在继续之前参阅
[启用使用 `RuntimeDefault` 作为所有工作负载的默认 seccomp 配置文件](#enable-runtimedefault-as-default)
<!--
Once you have a kind configuration in place, create the kind cluster with
that configuration:
-->
有了 kind 配置后,使用该配置创建 kind 集群:
```shell
kind create cluster --config=kind.yaml
```
<!--
After the new Kubernetes cluster is ready, identify the Docker container running
as the single node cluster:
-->
新的 Kubernetes 集群准备就绪后,找出作为单节点集群运行的 Docker 容器:
```shell
docker ps
```
<!--
You should see output indicating that a container is running with name
`kind-control-plane`. The output is similar to:
-->
你应该看到输出中名为 `kind-control-plane` 的容器正在运行。
输出类似于:
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6a96207fed4b kindest/node:v1.18.2 "/usr/local/bin/entr…" 27 seconds ago Up 24 seconds 127.0.0.1:42223->6443/tcp kind-control-plane
```
<!--
If observing the filesystem of that container, you should see that the
`profiles/` directory has been successfully loaded into the default seccomp path
of the kubelet. Use `docker exec` to run a command in the Pod:
-->
如果观察该容器的文件系统,
你应该会看到 `profiles/` 目录已成功加载到 kubelet 的默认 seccomp 路径中。
使用 `docker exec` 在 Pod 中运行命令:
```shell
# 将 6a96207fed4b 更改为你从 “docker ps” 看到的容器 ID
docker exec -it 6a96207fed4b ls /var/lib/kubelet/seccomp/profiles
```
```
audit.json fine-grained.json violation.json
```
<!--
You have verified that these seccomp profiles are available to the kubelet
running within kind.
-->
你已验证这些 seccomp 配置文件可用于在 kind 中运行的 kubelet。
<!--
## Enable the use of `RuntimeDefault` as the default seccomp profile for all workloads
-->
## 启用使用 `RuntimeDefault` 作为所有工作负载的默认 seccomp 配置文件 {#enable-runtimedefault-as-default}
{{< feature-state state="alpha" for_k8s_version="v1.22" >}}
<!--
`SeccompDefault` is an optional kubelet
[feature gate](/docs/reference/command-line-tools-reference/feature-gates) as
well as corresponding `--seccomp-default`
[command line flag](/docs/reference/command-line-tools-reference/kubelet).
Both have to be enabled simultaneously to use the feature.
-->
`SeccompDefault` 是一个可选的 kubelet [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates)
以及相应的 `--seccomp-default` [命令行标志](/zh/docs/reference/command-line-tools-reference/kubelet)。
两者必须同时启用才能使用该功能。
<!--
If enabled, the kubelet will use the `RuntimeDefault` seccomp profile by default, which is
defined by the container runtime, instead of using the `Unconfined` (seccomp disabled) mode.
The default profiles aim to provide a strong set
of security defaults while preserving the functionality of the workload. It is
possible that the default profiles differ between container runtimes and their
release versions, for example when comparing those from CRI-O and containerd.
-->
如果启用,kubelet 将会默认使用 `RuntimeDefault` seccomp 配置文件,
(这一配置文明是由容器运行时定义的),而不是使用 `Unconfined`(禁用 seccomp)模式。
默认的配置文件旨在提供一组限制性较强且能保留工作负载功能的安全默认值。
不同容器运行时及其不同发布版本之间的默认配置文件可能有所不同,
例如在比较来自 CRI-O 和 containerd 的配置文件时。
{{< note >}}
<!--
Enabling the feature will neither change the Kubernetes
`securityContext.seccompProfile` API field nor add the deprecated annotations of
the workload. This provides users the possibility to rollback anytime without
actually changing the workload configuration. Tools like
[`crictl inspect`](https://github.com/kubernetes-sigs/cri-tools) can be used to
verify which seccomp profile is being used by a container.
-->
启用该功能既不会更改 Kubernetes `securityContext.seccompProfile` API 字段,
也不会添加已弃用的工作负载注解。
这为用户提供了随时回滚的可能性,而且无需实际更改工作负载配置。
[`crictl inspect`](https://github.com/kubernetes-sigs/cri-tools)
之类的工具可用于验证容器正在使用哪个 seccomp 配置文件。
{{< /note >}}
<!--
Some workloads may require a lower amount of syscall restrictions than others.
This means that they can fail during runtime even with the `RuntimeDefault`
profile. To mitigate such a failure, you can:
- Run the workload explicitly as `Unconfined`.
- Disable the `SeccompDefault` feature for the nodes. Also making sure that
workloads get scheduled on nodes where the feature is disabled.
- Create a custom seccomp profile for the workload.
-->
与其他工作负载相比,某些工作负载可能需要更少的系统调用限制。
这意味着即使使用 `RuntimeDefault` 配置文件,它们也可能在运行时失败。
要应对此类故障,你可以:
- 将工作负载显式运行为 `Unconfined`
- 禁用节点的 `SeccompDefault` 功能。还要确保工作负载被调度到禁用该功能的节点上。
- 为工作负载创建自定义 seccomp 配置文件。
<!--
If you were introducing this feature into production-like cluster, the Kubernetes project
recommends that you enable this feature gate on a subset of your nodes and then
test workload execution before rolling the change out cluster-wide.
More detailed information about a possible upgrade and downgrade strategy can be
found in the [related Kubernetes Enhancement Proposal (KEP)](https://github.com/kubernetes/enhancements/tree/a70cc18/keps/sig-node/2413-seccomp-by-default#upgrade--downgrade-strategy).
-->
如果你将此功能引入到类似生产的集群中,
Kubernetes 项目建议你在部分节点上启用此特性门控,
然后在整个集群范围内推出更改之前,测试工作负载执行情况。
有关可能的升级和降级策略的更多详细信息,
请参阅[相关的 Kubernetes 增强提案 (KEP)](https://github.com/kubernetes/enhancements/tree/a70cc18/keps/sig-node/2413-seccomp-by-default#upgrade--downgrade-strategy)。
<!--
Since the feature is in alpha state it is disabled per default. To enable it,
pass the flags `--feature-gates=SeccompDefault=true --seccomp-default` to the
`kubelet` CLI or enable it via the [kubelet configuration
file](/docs/tasks/administer-cluster/kubelet-config-file/). To enable the
feature gate in [kind](https://kind.sigs.k8s.io), ensure that `kind` provides
the minimum required Kubernetes version and enables the `SeccompDefault` feature
[in the kind configuration](https://kind.sigs.k8s.io/docs/user/quick-start/#enable-feature-gates-in-your-cluster):
-->
由于此特性处于 alpha 阶段,默认是被禁用的。
要启用它,传递标志 `--feature-gates=SeccompDefault=true --seccomp-default`
kubelet CLI 或者通过 [kubelet 配置文件](/docs/tasks/administer-cluster/kubelet-config-file/)启用。
要在 [kind](https://kind.sigs.k8s.io) 启用特性门控,
请确保 `kind` 提供所需的最低 Kubernetes 版本,
并[在 kind 配置中](https://kind.sigs.k8s.io/docs/user/quick-start/#enable-feature-gates-in-your-cluster)
启用了 `SeccompDefault` 特性:
```yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
SeccompDefault: true
nodes:
- role: control-plane
image: kindest/node:v1.23.0@sha256:49824ab1727c04e56a21a5d8372a402fcd32ea51ac96a2706a12af38934f81ac
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
seccomp-default: "true"
- role: worker
image: kindest/node:v1.23.0@sha256:49824ab1727c04e56a21a5d8372a402fcd32ea51ac96a2706a12af38934f81ac
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
feature-gates: SeccompDefault=true
seccomp-default: "true"
```
<!-- If the cluster is ready, then running a pod: -->
如果集群已就绪,则运行一个 Pod
```shell
kubectl run --rm -it --restart=Never --image=alpine alpine -- sh
```
<!--
Should now have the default seccomp profile attached. This can be verified by
using `docker exec` to run `crictl inspect` for the container on the kind
worker:
-->
现在应该附加了默认的 seccomp 配置文件。
这可以通过使用 `docker exec` 为 kind 上的容器运行 `crictl inspect` 来验证:
```shell
docker exec -it kind-worker bash -c \
'crictl inspect $(crictl ps --name=alpine -q) | jq .info.runtimeSpec.linux.seccomp'
```
```json
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32"],
"syscalls": [
{
"names": ["..."]
}
]
}
```
<!--
## Create a Pod with a seccomp profile for syscall auditing
To start off, apply the `audit.json` profile, which will log all syscalls of the
process, to a new Pod.
Here's a manifest for that Pod:
-->
## 使用 seccomp 配置文件创建 Pod 以进行系统调用审计 {#create-a-pod-with-a-seccomp-profile-for-syscall-auditing}
首先,将 `audit.json` 配置文件应用到新的 Pod 上,该配置文件将记录进程的所有系统调用。
这是该 Pod 的清单:
{{< codenew file="pods/security/seccomp/ga/audit-pod.yaml" >}}
{{< note >}}
<!--
The functional support for the already deprecated seccomp annotations
`seccomp.security.alpha.kubernetes.io/pod` (for the whole pod) and
`container.seccomp.security.alpha.kubernetes.io/[name]` (for a single container)
is going to be removed with the release of Kubernetes v1.25. Please always use
the native API fields in favor of the annotations.
-->
已弃用的 seccomp 注解 `seccomp.security.alpha.kubernetes.io/pod`(针对整个 Pod)和
`container.seccomp.security.alpha.kubernetes.io/[name]`(针对单个容器)
将随着 Kubernetes v1.25 的发布而被删除。
请在可能的情况下使用原生 API 字段而不是注解。
{{< /note >}}
<!-- Create the Pod in the cluster: -->
在集群中创建 Pod
```shell
kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/audit-pod.yaml
```
<!--
This profile does not restrict any syscalls, so the Pod should start
successfully.
-->
此配置文件不限制任何系统调用,因此 Pod 应该成功启动。
```shell
kubectl get pod/audit-pod
```
```
NAME READY STATUS RESTARTS AGE
audit-pod 1/1 Running 0 30s
```
<!--
In order to be able to interact with this endpoint exposed by this
container, create a NodePort {{< glossary_tooltip text="Services" term_id="service" >}}
that allows access to the endpoint from inside the kind control plane container.
-->
为了能够与容器暴露的端点交互,
创建一个 NodePort 类型的 {{< glossary_tooltip text="Service" term_id="service" >}}
允许从 kind 控制平面容器内部访问端点。
```shell
kubectl expose pod audit-pod --type NodePort --port 5678
```
<!-- Check what port the Service has been assigned on the node. -->
检查 Service 在节点上分配的端口。
```shell
kubectl get service audit-pod
```
<!-- The output is similar to: -->
输出类似于:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
audit-pod NodePort 10.111.36.142 <none> 5678:32373/TCP 72s
```
<!--
Now you can use `curl` to access that endpoint from inside the kind control plane container,
at the port exposed by this Service. Use `docker exec` to run the `curl` command within the
container belonging to that control plane container:
-->
现在,你可以使用 `curl` 从 kind 控制平面容器内部访问该端点,位于该服务所公开的端口上。
使用 `docker exec` 在属于该控制平面容器的容器中运行 `curl` 命令:
```shell
# 将 6a96207fed4b 更改为你从 “docker ps” 看到的控制平面容器 ID
docker exec -it 6a96207fed4b curl localhost:32373
```
```
just made some syscalls!
```
<!--
You can see that the process is running, but what syscalls did it actually make?
Because this Pod is running in a local cluster, you should be able to see those
in `/var/log/syslog`. Open up a new terminal window and `tail` the output for
calls from `http-echo`:
-->
你可以看到该进程正在运行,但它实际上进行了哪些系统调用?
因为这个 Pod 在本地集群中运行,你应该能够在 `/var/log/syslog` 中看到它们。
打开一个新的终端窗口并 `tail` 来自 `http-echo` 的调用的输出:
```shell
tail -f /var/log/syslog | grep 'http-echo'
```
<!--
You should already see some logs of syscalls made by `http-echo`, and if you
`curl` the endpoint in the control plane container you will see more written.
For example:
-->
你应该已经看到了一些由 `http-echo` 进行的系统调用的日志,
如果你在控制平面容器中 `curl` 端点,你会看到更多的写入。
例如:
```
Jul 6 15:37:40 my-machine kernel: [369128.669452] audit: type=1326 audit(1594067860.484:14536): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=51 compat=0 ip=0x46fe1f code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669453] audit: type=1326 audit(1594067860.484:14537): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=54 compat=0 ip=0x46fdba code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669455] audit: type=1326 audit(1594067860.484:14538): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669456] audit: type=1326 audit(1594067860.484:14539): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=288 compat=0 ip=0x46fdba code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669517] audit: type=1326 audit(1594067860.484:14540): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=0 compat=0 ip=0x46fd44 code=0x7ffc0000
Jul 6 15:37:40 my-machine kernel: [369128.669519] audit: type=1326 audit(1594067860.484:14541): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000
Jul 6 15:38:40 my-machine kernel: [369188.671648] audit: type=1326 audit(1594067920.488:14559): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000
Jul 6 15:38:40 my-machine kernel: [369188.671726] audit: type=1326 audit(1594067920.488:14560): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000
```
<!--
You can begin to understand the syscalls required by the `http-echo` process by
looking at the `syscall=` entry on each line. While these are unlikely to
encompass all syscalls it uses, it can serve as a basis for a seccomp profile
for this container.
Clean up that Pod and Service before moving to the next section:
-->
通过查看每一行的 `syscall=` 条目,你可以开始了解 `http-echo` 进程所需的系统调用。
虽然这些不太可能包含它使用的所有系统调用,但它可以作为此容器的 seccomp 配置文件的基础。
在转到下一部分之前清理该 Pod 和 Service
```shell
kubectl delete service audit-pod --wait
kubectl delete pod audit-pod --wait --now
```
<!--
## Create Pod with seccomp profile that causes violation
For demonstration, apply a profile to the Pod that does not allow for any
syscalls.
The manifest for this demonstration is:
-->
## 使用导致违规的 seccomp 配置文件创建 Pod {#create-pod-with-seccomp-profile-that-causes-violation}
出于演示目的,将配置文件应用于不允许任何系统调用的 Pod 上。
此演示的清单是:
{{< codenew file="pods/security/seccomp/ga/violation-pod.yaml" >}}
<!-- Attempt to create the Pod in the cluster: -->
尝试在集群中创建 Pod
```shell
kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/violation-pod.yaml
```
<!--
The Pod creates, but there is an issue.
If you check the status of the Pod, you should see that it failed to start.
-->
Pod 创建,但存在问题。
如果你检查 Pod 状态,你应该看到它没有启动。
```shell
kubectl get pod/violation-pod
```
```
NAME READY STATUS RESTARTS AGE
violation-pod 0/1 CrashLoopBackOff 1 6s
```
<!--
As seen in the previous example, the `http-echo` process requires quite a few
syscalls. Here seccomp has been instructed to error on any syscall by setting
`"defaultAction": "SCMP_ACT_ERRNO"`. This is extremely secure, but removes the
ability to do anything meaningful. What you really want is to give workloads
only the privileges they need.
Clean up that Pod before moving to the next section:
-->
如上例所示,`http-echo` 进程需要相当多的系统调用。
这里 seccomp 已通过设置 `"defaultAction": "SCMP_ACT_ERRNO"` 被指示为在发生任何系统调用时报错。
这是非常安全的,但消除了做任何有意义的事情的能力。
你真正想要的是只给工作负载它们所需要的权限。
在转到下一部分之前清理该 Pod
```shell
kubectl delete pod violation-pod --wait --now
```
<!--
## Create Pod with seccomp profile that only allows necessary syscalls
If you take a look at the `fine-grained.json` profile, you will notice some of the syscalls
seen in syslog of the first example where the profile set `"defaultAction":
"SCMP_ACT_LOG"`. Now the profile is setting `"defaultAction": "SCMP_ACT_ERRNO"`,
but explicitly allowing a set of syscalls in the `"action": "SCMP_ACT_ALLOW"`
block. Ideally, the container will run successfully and you will see no messages
sent to `syslog`.
The manifest for this example is:
-->
## 使用只允许必要的系统调用的 seccomp 配置文件创建 Pod {#create-pod-with-seccomp-profile-that-only-allows-necessary-syscalls}
如果你看一看 `fine-grained.json` 配置文件,
你会注意到第一个示例的 syslog 中看到的一些系统调用,
其中配置文件设置为 `"defaultAction": "SCMP_ACT_LOG"`
现在的配置文件设置 `"defaultAction": "SCMP_ACT_ERRNO"`,
但在 `"action": "SCMP_ACT_ALLOW"` 块中明确允许一组系统调用。
理想情况下,容器将成功运行,并且你看到没有消息发送到 `syslog`
此示例的清单是:
{{< codenew file="pods/security/seccomp/ga/fine-pod.yaml" >}}
<!-- Create the Pod in your cluster: -->
在你的集群中创建 Pod
```shell
kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/fine-pod.yaml
```
```shell
kubectl get pod fine-pod
```
<!-- The Pod should be showing as having started successfully: -->
此 Pod 应该显示为已成功启动:
```
NAME READY STATUS RESTARTS AGE
fine-pod 1/1 Running 0 30s
```
<!--
Open up a new terminal window and use `tail` to monitor for log entries that
mention calls from `http-echo`:
-->
打开一个新的终端窗口并使用 `tail` 来监视提到来自 `http-echo` 的调用的日志条目:
```shell
# 你计算机上的日志路径可能与 “/var/log/syslog” 不同
tail -f /var/log/syslog | grep 'http-echo'
```
<!-- Next, expose the Pod with a NodePort Service: -->
接着,使用 NodePort Service 公开 Pod
```shell
kubectl expose pod fine-pod --type NodePort --port 5678
```
<!-- Check what port the Service has been assigned on the node: -->
检查节点上的 Service 分配了什么端口:
```shell
kubectl get service fine-pod
```
<!-- The output is similar to: -->
输出类似于:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fine-pod NodePort 10.111.36.142 <none> 5678:32373/TCP 72s
```
<!-- Use `curl` to access that endpoint from inside the kind control plane container: -->
使用 `curl` 从 kind 控制平面容器内部访问端点:
```shell
# 将 6a96207fed4b 更改为你从 “docker ps” 看到的控制平面容器 ID
docker exec -it 6a96207fed4b curl localhost:32373
```
```
just made some syscalls!
```
<!--
You should see no output in the `syslog`. This is because the profile allowed all
necessary syscalls and specified that an error should occur if one outside of
the list is invoked. This is an ideal situation from a security perspective, but
required some effort in analyzing the program. It would be nice if there was a
simple way to get closer to this security without requiring as much effort.
Clean up that Pod and Service before moving to the next section:
-->
你应该在 `syslog` 中看不到任何输出。
这是因为配置文件允许所有必要的系统调用,并指定如果调用列表之外的系统调用应发生错误。
从安全角度来看,这是一种理想的情况,但需要在分析程序时付出一些努力。
如果有一种简单的方法可以在不需要太多努力的情况下更接近这种安全性,那就太好了。
在转到下一部分之前清理该 Pod 和服务:
```shell
kubectl delete service fine-pod --wait
kubectl delete pod fine-pod --wait --now
```
<!--
## Create Pod that uses the container runtime default seccomp profile
Most container runtimes provide a sane set of default syscalls that are allowed
or not. You can adopt these defaults for your workload by setting the seccomp
type in the security context of a pod or container to `RuntimeDefault`.
-->
## 创建使用容器运行时默认 seccomp 配置文件的 Pod {#create-pod-that-uses-the-container-runtime-default-seccomp-profile}
大多数容器运行时都提供了一组合理的默认系统调用,以及是否允许执行这些系统调用。
你可以通过将 Pod 或容器的安全上下文中的 seccomp 类型设置为 `RuntimeDefault`
来为你的工作负载采用这些默认值。
{{< note >}}
<!--
If you have the `SeccompDefault` [feature gate](/docs/reference/command-line-tools-reference/feature-gates/) enabled, then Pods use the `RuntimeDefault` seccomp profile whenever
no other seccomp profile is specified. Otherwise, the default is `Unconfined`.
-->
如果你已经启用了 `SeccompDefault` [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)
只要没有指定其他 seccomp 配置文件,那么 Pod 就会使用 `SeccompDefault` 的 seccomp 配置文件。
否则,默认值为 `Unconfined`
{{< /note >}}
<!--
Here's a manifest for a Pod that requests the `RuntimeDefault` seccomp profile
for all its containers:
-->
这是一个 Pod 的清单,它要求其所有容器使用 `RuntimeDefault` seccomp 配置文件:
{{< codenew file="pods/security/seccomp/ga/default-pod.yaml" >}}
<!-- Create that Pod: -->
创建此 Pod
```shell
kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/default-pod.yaml
```
```shell
kubectl get pod default-pod
```
<!-- The Pod should be showing as having started successfully: -->
此 Pod 应该显示为成功启动:
```
NAME READY STATUS RESTARTS AGE
default-pod 1/1 Running 0 20s
```
<!-- Finally, now that you saw that work OK, clean up: -->
最后,你看到一切正常之后,请清理:
```shell
kubectl delete pod default-pod --wait --now
```
## {{% heading "whatsnext" %}}
<!--
You can learn more about Linux seccomp:
* [A seccomp Overview](https://lwn.net/Articles/656307/)
* [Seccomp Security Profiles for Docker](https://docs.docker.com/engine/security/seccomp/)
-->
你可以了解有关 Linux seccomp 的更多信息:
* [seccomp 概述](https://lwn.net/Articles/656307/)
* [Docker 的 Seccomp 安全配置文件](https://docs.docker.com/engine/security/seccomp/)
@@ -0,0 +1,4 @@
---
title: "Services"
weight: 70
---
@@ -0,0 +1,405 @@
---
title: 使用 Source IP
content_type: tutorial
---
<!-- overview -->
Kubernetes 集群中运行的应用通过 Service 抽象来互相查找、通信和与外部世界沟通。本文介绍被发送到不同类型 Services 的数据包源 IP 的变化过程,你可以根据你的需求改变这些行为。
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
## 术语表
本文使用了下列术语:
* [NAT](https://en.wikipedia.org/wiki/Network_address_translation): 网络地址转换
* [Source NAT](https://en.wikipedia.org/wiki/Network_address_translation#SNAT): 替换数据包的源 IP, 通常为节点的 IP
* [Destination NAT](https://en.wikipedia.org/wiki/Network_address_translation#DNAT): 替换数据包的目的 IP, 通常为 Pod 的 IP
* [VIP](/zh/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 一个虚拟 IP, 例如分配给每个 Kubernetes Service 的 IP
* [Kube-proxy](/zh/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 一个网络守护程序,在每个节点上协调 Service VIP 管理
## 准备工作
你必须拥有一个正常工作的 Kubernetes 1.5 集群来运行此文档中的示例。该示例使用一个简单的 nginx webserver,通过一个HTTP消息头返回它接收到请求的源IP。你可以像下面这样创建它:
```console
kubectl create deployment source-ip-app --image=k8s.gcr.io/echoserver:1.4
```
输出结果为
```
deployment.apps/source-ip-app created
```
## {{% heading "objectives" %}}
* 通过多种类型的 Services 暴露一个简单应用
* 理解每种 Service 类型如何处理源 IP NAT
* 理解保留源IP所涉及的折中
<!-- lessoncontent -->
## Type=ClusterIP 类型 Services 的 Source IP
如果你的 kube-proxy 运行在 [iptables 模式](/zh/docs/user-guide/services/#proxy-mode-iptables)下,从集群内部发送到 ClusterIP 的包永远不会进行源地址 NAT,这从 Kubernetes 1.2 开始是默认选项。Kube-proxy 通过一个 `proxyMode` endpoint 暴露它的模式。
```console
kubectl get nodes
```
输出结果与以下结果类似:
```
NAME STATUS ROLES AGE VERSION
kubernetes-node-6jst Ready <none> 2h v1.13.0
kubernetes-node-cx31 Ready <none> 2h v1.13.0
kubernetes-node-jj1t Ready <none> 2h v1.13.0
```
从其中一个节点中得到代理模式
```console
kubernetes-node-6jst $ curl localhost:10249/proxyMode
```
输出结果为:
```
iptables
```
你可以通过在source IP应用上创建一个Service来测试源IP保留。
```console
kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
```
输出结果为:
```
service/clusterip exposed
```
```console
kubectl get svc clusterip
```
输出结果与以下结果类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip ClusterIP 10.0.170.92 <none> 80/TCP 51s
```
从相同集群中的一个 pod 访问这个 `ClusterIP`
```shell
kubectl run busybox -it --image=busybox:1.28 --restart=Never --rm
```
输出结果与以下结果类似:
```
Waiting for pod default/busybox to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
```
然后你可以在 Pod 内运行命令:
```shell
# 在终端内使用"kubectl run"执行
ip addr
```
```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue
link/ether 0a:58:0a:f4:03:08 brd ff:ff:ff:ff:ff:ff
inet 10.244.3.8/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::188a:84ff:feb0:26a5/64 scope link
valid_lft forever preferred_lft forever
```
然后使用 `wget` 去请求本地 Web 服务器
```shell
# 用名为 "clusterip" 的服务的 IPv4 地址替换 "10.0.170.92"
wget -qO - 10.0.170.92
```
```
CLIENT VALUES:
client_address=10.244.3.8
command=GET
...
```
无论客户端 pod 和 服务端 pod 是否在相同的节点上,client_address 始终是客户端 pod 的 IP 地址。
## Type=NodePort 类型 Services 的 Source IP
从 Kubernetes 1.5 开始,发送给类型为 [Type=NodePort](/zh/docs/user-guide/services/#nodeport) Services 的数据包默认进行源地址 NAT。你可以通过创建一个 `NodePort` Service 来进行测试:
```console
kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
```
输出结果为:
```
service/nodeport exposed
```
```console
NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }')
```
如果你的集群运行在一个云服务上,你可能需要为上面报告的 `nodes:nodeport` 开启一条防火墙规则。
现在,你可以通过上面分配的节点端口从外部访问这个 Service。
```console
for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done
```
输出结果与以下结果类似:
```
client_address=10.180.1.1
client_address=10.240.0.5
client_address=10.240.0.3
```
请注意,这些并不是正确的客户端 IP,它们是集群的内部 IP。这是所发生的事情:
* 客户端发送数据包到 `node2:nodePort`
* `node2` 使用它自己的 IP 地址替换数据包的源 IP 地址(SNAT)
* `node2` 使用 pod IP 地址替换数据包的目的 IP 地址
* 数据包被路由到 node 1,然后交给 endpoint
* Pod 的回复被路由回 node2
* Pod 的回复被发送回给客户端
用图表示:
{{< mermaid >}}
graph LR;
client(client)-->node2[节点 2];
node2-->client;
node2-. SNAT .->node1[节点 1];
node1-. SNAT .->node2;
node1-->endpoint(端点);
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
class node1,node2,endpoint k8s;
class client plain;
{{</ mermaid >}}
为了防止这种情况发生,Kubernetes 提供了一个特性来保留客户端的源 IP 地址[(点击此处查看可用特性)](/zh/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip)。设置 `service.spec.externalTrafficPolicy` 的值为 `Local`,请求就只会被代理到本地 endpoints 而不会被转发到其它节点。这样就保留了最初的源 IP 地址。如果没有本地 endpoints,发送到这个节点的数据包将会被丢弃。这样在应用到数据包的任何包处理规则下,你都能依赖这个正确的 source-ip 使数据包通过并到达 endpoint。
设置 `service.spec.externalTrafficPolicy` 字段如下:
```console
kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'
```
输出结果为:
```
service/nodeport patched
```
现在,重新运行测试:
```console
for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done
```
输出结果为:
```
client_address=104.132.1.79
```
请注意,你只从 endpoint pod 运行的那个节点得到了一个回复,这个回复有*正确的*客户端 IP。
这是发生的事情:
* 客户端发送数据包到 `node2:nodePort`,它没有任何 endpoints
* 数据包被丢弃
* 客户端发送数据包到 `node1:nodePort`,它*有*endpoints
* node1 使用正确的源 IP 地址将数据包路由到 endpoint
用图表示:
{{< mermaid >}}
graph TD;
client --> node1[节点 1];
client(client) --x node2[节点 2];
node1 --> endpoint(端点);
endpoint --> node1;
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
class node1,node2,endpoint k8s;
class client plain;
{{</ mermaid >}}
## Type=LoadBalancer 类型 Services 的 Source IP
从Kubernetes1.5开始,发送给类型为 [Type=LoadBalancer](/zh/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT,这是因为所有处于 `Ready` 状态的可调度 Kubernetes 节点对于负载均衡的流量都是符合条件的。所以如果数据包到达一个没有 endpoint 的节点,系统将把这个包代理到*有* endpoint 的节点,并替换数据包的源 IP 为节点的 IP(如前面章节所述)。
你可以通过在一个 loadbalancer 上暴露这个 source-ip-app 来进行测试。
```console
kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer
```
输出结果为:
```
service/loadbalancer exposed
```
打印Service的IPs
```console
kubectl get svc loadbalancer
```
输出结果与以下结果类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loadbalancer LoadBalancer 10.0.65.118 104.198.149.140 80/TCP 5m
```
```console
curl 104.198.149.140
```
输出结果与以下结果类似:
```
CLIENT VALUES:
client_address=10.240.0.5
...
```
然而,如果你的集群运行在 Google Kubernetes Engine/GCE 上,可以通过设置 service.spec.externalTrafficPolicy 字段值为 Local ,故意导致健康检查失败来强制使没有 endpoints 的节点把自己从负载均衡流量的可选节点列表中删除。
用图表示:
![Source IP with externalTrafficPolicy](/images/docs/sourceip-externaltrafficpolicy.svg)
你可以设置 annotation 来进行测试:
```console
kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}'
```
你应该能够立即看到 Kubernetes 分配的 `service.spec.healthCheckNodePort` 字段:
```console
kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort
```
输出结果与以下结果类似:
```
healthCheckNodePort: 32122
```
`service.spec.healthCheckNodePort` 字段指向每个节点在 `/healthz` 路径上提供的用于健康检查的端口。你可以这样测试:
```console
kubectl get pod -o wide -l run=source-ip-app
```
输出结果与以下结果类似:
```
NAME READY STATUS RESTARTS AGE IP NODE
source-ip-app-826191075-qehz4 1/1 Running 0 20h 10.180.1.136 kubernetes-node-6jst
```
使用 curl 命令发送请求到每个节点的 `/healthz` 路径。
```console
kubernetes-node-6jst $ curl localhost:32122/healthz
```
输出结果与以下结果类似:
```
1 Service Endpoints found
```
```console
kubernetes-node-jj1t $ curl localhost:32122/healthz
```
输出结果与以下结果类似:
```
No Service Endpoints Found
```
主节点运行的 service 控制器负责分配 cloud loadbalancer。在这样做的同时,它也会分配指向每个节点的 HTTP 健康检查的 port/path。等待大约 10 秒钟之后,没有 endpoints 的两个节点的健康检查会失败,然后 curl 负载均衡器的 ip:
```console
curl 104.198.149.140
```
输出结果与以下结果类似:
```
CLIENT VALUES:
client_address=104.132.1.79
...
```
__跨平台支持__
从 Kubernetes 1.5 开始,通过类型为 Type=LoadBalancer 的 Services 进行源 IP 保存的支持仅在一部分 cloudproviders 中实现(GCP and Azure)。你的集群运行的 cloudprovider 可能以某些不同的方式满足 loadbalancer 的要求:
1. 使用一个代理终止客户端连接并打开一个到你的 nodes/endpoints 的新连接。在这种情况下,源 IP 地址将永远是云负载均衡器的地址而不是客户端的。
2. 使用一个包转发器,因此从客户端发送到负载均衡器 VIP 的请求在拥有客户端源 IP 地址的节点终止,而不被中间代理。
第一类负载均衡器必须使用一种它和后端之间约定的协议来和真实的客户端 IP 通信,例如 HTTP [X-FORWARDED-FOR](https://en.wikipedia.org/wiki/X-Forwarded-For) 头,或者 [proxy 协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
第二类负载均衡器可以通过简单的在保存于 Service 的 `service.spec.healthCheckNodePort` 字段上创建一个 HTTP 健康检查点来使用上面描述的特性。
## {{% heading "cleanup" %}}
删除服务:
```console
$ kubectl delete svc -l app=source-ip-app
```
删除 Deployment、ReplicaSet 和 Pod
```console
$ kubectl delete deployment source-ip-app
```
## {{% heading "whatsnext" %}}
* 进一步学习 [通过 services 连接应用](/zh/docs/concepts/services-networking/connect-applications-service/)
@@ -0,0 +1,4 @@
---
title: "有状态的应用"
weight: 50
---
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,444 @@
---
title: "示例:使用 StatefulSet 部署 Cassandra"
content_type: tutorial
weight: 30
---
<!--
title: "Example: Deploying Cassandra with a StatefulSet"
reviewers:
- ahmetb
content_type: tutorial
weight: 30
-->
<!-- overview -->
<!--
This tutorial shows you how to run [Apache Cassandra](https://cassandra.apache.org/) on Kubernetes.
Cassandra, a database, needs persistent storage to provide data durability (application _state_).
In this example, a custom Cassandra seed provider lets the database discover new Cassandra instances as they join the Cassandra cluster.
-->
本教程描述拉如何在 Kubernetes 上运行 [Apache Cassandra](https://cassandra.apache.org/)。
数据库 Cassandra 需要永久性存储提供数据持久性(应用“状态”)。
在此示例中,自定义 Cassandra seed provider 使数据库在加入 Cassandra
集群时发现新的 Cassandra 实例。
<!--
*StatefulSets* make it easier to deploy stateful applications into your Kubernetes cluster.
For more information on the features used in this tutorial, see
[StatefulSet](/docs/concepts/workloads/controllers/statefulset/).
-->
使用"StatefulSets"可以更轻松地将有状态的应用程序部署到你的 Kubernetes 集群中。
有关本教程中使用的功能的更多信息,
参阅 [StatefulSet](/zh/docs/concepts/workloads/controllers/statefulset/)。
{{< note >}}
<!--
Cassandra and Kubernetes both use the term _node_ to mean a member of a cluster. In this
tutorial, the Pods that belong to the StatefulSet are Cassandra nodes and are members
of the Cassandra cluster (called a _ring_). When those Pods run in your Kubernetes cluster,
the Kubernetes control plane schedules those Pods onto Kubernetes
{{< glossary_tooltip text="Nodes" term_id="node" >}}.
-->
Cassandra 和 Kubernetes 都使用术语“节点(node)”来表示集群的成员。
在本教程中,属于 StatefulSet 的 Pod 是 Cassandra 节点,并且是 Cassandra 集群的成员(称为 “ring”)。
当这些 Pod 在你的 Kubernetes 集群中运行时,Kubernetes 控制平面会将这些 Pod 调度到 Kubernetes 的
{{< glossary_tooltip text="节点" term_id="node" >}}上。
<!--
When a Cassandra node starts, it uses a _seed list_ to bootstrap discovery of other
nodes in the ring.
This tutorial deploys a custom Cassandra seed provider that lets the database discover
new Cassandra Pods as they appear inside your Kubernetes cluster.
-->
当 Cassandra 节点启动时,使用 _seed列表_ 来引导发现 ring 中其他节点。
本教程部署了一个自定义的 Cassandra seed provider,使数据库可以发现新的 Cassandra Pod
出现在 Kubernetes 集群中。
{{< /note >}}
## {{% heading "objectives" %}}
<!--
* Create and validate a Cassandra headless {{< glossary_tooltip text="Service" term_id="service" >}}.
* Use a {{< glossary_tooltip term_id="StatefulSet" >}} to create a Cassandra ring.
* Validate the StatefulSet.
* Modify the StatefulSet.
* Delete the StatefulSet and its {{< glossary_tooltip text="Pods" term_id="pod" >}}.
-->
* 创建并验证 Cassandra 无头(headless{{< glossary_tooltip text="Service" term_id="service" >}}..
* 使用 {{< glossary_tooltip term_id="StatefulSet" >}} 创建一个 Cassandra ring。
* 验证 StatefulSet。
* 修改 StatefulSet。
* 删除 StatefulSet 及其 {{< glossary_tooltip text="Pod" term_id="pod" >}}.
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}}
<!--
To complete this tutorial, you should already have a basic familiarity with
{{< glossary_tooltip text="Pods" term_id="pod" >}},
{{< glossary_tooltip text="Services" term_id="service" >}}, and
{{< glossary_tooltip text="StatefulSets" term_id="StatefulSet" >}}.
-->
要完成本教程,你应该已经熟悉 {{< glossary_tooltip text="Pod" term_id="pod" >}}
{{< glossary_tooltip text="Service" term_id="service" >}} 和
{{< glossary_tooltip text="StatefulSet" term_id="StatefulSet" >}}。
<!--
### Additional Minikube setup instructions
{{< caution >}}
[Minikube](https://minikube.sigs.k8s.io/docs/) defaults to 2048MB of memory and 2 CPU.
Running Minikube with the default resource configuration results in insufficient resource
errors during this tutorial. To avoid these errors, start Minikube with the following settings:
-->
### 额外的 Minikube 设置说明
{{< caution >}}
[Minikube](https://minikube.sigs.k8s.io/docs/)默认为 2048MB 内存和 2 个 CPU。
在本教程中,使用默认资源配置运行 Minikube 会导致资源不足的错误。为避免这些错误,请使用以下设置启动 Minikube:
```shell
minikube start --memory 5120 --cpus=4
```
{{< /caution >}}
<!-- lessoncontent -->
<!--
## Creating a headless Service for Cassandra {#creating-a-cassandra-headless-service}
In Kubernetes, a {{< glossary_tooltip text="Service" term_id="service" >}} describes a set of
{{< glossary_tooltip text="Pods" term_id="pod" >}} that perform the same task.
The following Service is used for DNS lookups between Cassandra Pods and clients within your cluster:
Create a Service to track all Cassandra StatefulSet members from the `cassandra-service.yaml` file:
-->
## 为 Cassandra 创建无头(headless Services {#creating-a-cassandra-headless-service}
在 Kubernetes 中,一个 {{< glossary_tooltip text="Service" term_id="service" >}}
描述了一组执行相同任务的 {{< glossary_tooltip text="Pod" term_id="pod" >}}。
以下 Service 用于在 Cassandra Pod 和集群中的客户端之间进行 DNS 查找:
{{< codenew file="application/cassandra/cassandra-service.yaml" >}}
创建一个 Service 来跟踪 `cassandra-service.yaml` 文件中的所有 Cassandra StatefulSet
```shell
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml
```
<!--
### Validating (optional) {#validating}
Get the Cassandra Service.
-->
### 验证(可选) {#validating}
获取 Cassandra Service。
```shell
kubectl get svc cassandra
```
<!--
The response is
-->
响应是:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cassandra ClusterIP None <none> 9042/TCP 45s
```
<!--
If you don't see a Service named `cassandra`, that means creation failed. Read
[Debug Services](/docs/tasks/debug/debug-application/debug-service/)
for help troubleshooting common issues.
-->
如果没有看到名为 `cassandra` 的服务,则表示创建失败。
请阅读[调试服务](/zh/docs/tasks/debug/debug-application/debug-service/),以解决常见问题。
<!--
## Using a StatefulSet to create a Cassandra ring
The StatefulSet manifest, included below, creates a Cassandra ring that consists of three Pods.
{{< note >}}
This example uses the default provisioner for Minikube.
Please update the following StatefulSet for the cloud you are working with.
{{< /note >}}
-->
## 使用 StatefulSet 创建 Cassandra Ring
下面包含的 StatefulSet 清单创建了一个由三个 Pod 组成的 Cassandra ring。
{{< note >}}
本示例使用 Minikube 的默认配置程序。
请为正在使用的云更新以下 StatefulSet。
{{< /note >}}
{{< codenew file="application/cassandra/cassandra-statefulset.yaml" >}}
<!--
Create the Cassandra StatefulSet from the `cassandra-statefulset.yaml` file:
-->
使用 `cassandra-statefulset.yaml` 文件创建 Cassandra StatefulSet
```shell
# 如果你能未经修改地 apply cassandra-statefulset.yaml,请使用此命令
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml
```
<!--
If you need to modify `cassandra-statefulset.yaml` to suit your cluster, download
https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml and then apply
that manifest, from the folder you saved the modified version into:
-->
如果你为了适合你的集群需要修改 `cassandra-statefulset.yaml`
下载 https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml
然后 apply 修改后的清单。
```shell
# 如果使用本地的 cassandra-statefulset.yaml ,请使用此命令
kubectl apply -f cassandra-statefulset.yaml
```
<!--
## Validating the Cassandra StatefulSet
1. Get the Cassandra StatefulSet:
-->
## 验证 Cassandra StatefulSet
1. 获取 Cassandra StatefulSet:
```shell
kubectl get statefulset cassandra
```
<!--
The response should be similar to:
-->
响应应该与此类似:
```
NAME DESIRED CURRENT AGE
cassandra 3 0 13s
```
<!--
The `StatefulSet` resource deploys Pods sequentially.
-->
`StatefulSet` 资源会按顺序部署 Pod。
<!--
1. Get the Pods to see the ordered creation status:
-->
2. 获取 Pod 查看已排序的创建状态:
```shell
kubectl get pods -l="app=cassandra"
```
<!--
The response should be similar to:
-->
响应应该与此类似:
```
NAME READY STATUS RESTARTS AGE
cassandra-0 1/1 Running 0 1m
cassandra-1 0/1 ContainerCreating 0 8s
```
<!--
It can take several minutes for all three Pods to deploy. Once they are deployed, the same command
returns output similar to:
-->
这三个 Pod 要花几分钟的时间才能部署。部署之后,相同的命令将返回类似于以下的输出:
```
NAME READY STATUS RESTARTS AGE
cassandra-0 1/1 Running 0 10m
cassandra-1 1/1 Running 0 9m
cassandra-2 1/1 Running 0 8m
```
<!--
3. Run the Cassandra [nodetool](https://cwiki.apache.org/confluence/display/CASSANDRA2/NodeTool) inside the first Pod, to
display the status of the ring.
-->
3. 运行第一个 Pod 中的 Cassandra [nodetool](https://cwiki.apache.org/confluence/display/CASSANDRA2/NodeTool)
以显示 ring 的状态。
```shell
kubectl exec -it cassandra-0 -- nodetool status
```
<!--
The response should be similar to:
-->
响应应该与此类似:
```
Datacenter: DC1-K8Demo
======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 172.17.0.5 83.57 KiB 32 74.0% e2dd09e6-d9d3-477e-96c5-45094c08db0f Rack1-K8Demo
UN 172.17.0.4 101.04 KiB 32 58.8% f89d6835-3a42-4419-92b3-0e62cae1479c Rack1-K8Demo
UN 172.17.0.6 84.74 KiB 32 67.1% a6a1e8c2-3dc5-4417-b1a0-26507af2aaad Rack1-K8Demo
```
<!--
## Modifying the Cassandra StatefulSet
Use `kubectl edit` to modify the size of a Cassandra StatefulSet.
1. Run the following command:
-->
## 修改 Cassandra StatefulSet
使用 `kubectl edit` 修改 Cassandra StatefulSet 的大小。
1. 运行以下命令:
```shell
kubectl edit statefulset cassandra
```
<!--
This command opens an editor in your terminal. The line you need to change is the `replicas` field.
The following sample is an excerpt of the StatefulSet file:
-->
此命令你的终端中打开一个编辑器。需要更改的是 `replicas` 字段。下面是 StatefulSet 文件的片段示例:
```yaml
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: StatefulSet
metadata:
creationTimestamp: 2016-08-13T18:40:58Z
generation: 1
labels:
app: cassandra
name: cassandra
namespace: default
resourceVersion: "323"
uid: 7a219483-6185-11e6-a910-42010a8a0fc0
spec:
replicas: 3
```
<!--
1. Change the number of replicas to 4, and then save the manifest.
The StatefulSet now scales to run with 4 Pods.
1. Get the Cassandra StatefulSet to verify your change:
-->
2. 将副本数(replicas)更改为 4,然后保存清单。
StatefulSet 现在可以扩展到运行 4 个 Pod。
3. 获取 Cassandra StatefulSet 验证更改:
```shell
kubectl get statefulset cassandra
```
<!--
The response should be similar to:
-->
响应应该与此类似:
```
NAME DESIRED CURRENT AGE
cassandra 4 4 36m
```
## {{% heading "cleanup" %}}
<!--
Deleting or scaling a StatefulSet down does not delete the volumes associated with the StatefulSet.
This setting is for your safety because your data is more valuable than automatically purging all related StatefulSet resources.
-->
删除或缩小 StatefulSet 不会删除与 StatefulSet 关联的卷。
这个设置是出于安全考虑,因为你的数据比自动清除所有相关的 StatefulSet 资源更有价值。
{{< warning >}}
<!--
Depending on the storage class and reclaim policy, deleting the *PersistentVolumeClaims* may cause the associated volumes
to also be deleted. Never assume you'll be able to access data if its volume claims are deleted.
-->
根据存储类和回收策略,删除 *PersistentVolumeClaims* 可能导致关联的卷也被删除。
千万不要认为其容量声明被删除,你就能访问数据。
{{< /warning >}}
<!--
1. Run the following commands (chained together into a single command) to delete everything in the Cassandra StatefulSet:
-->
1. 运行以下命令(连在一起成为一个单独的命令)删除 Cassandra StatefulSet 中的所有内容:
```shell
grace=$(kubectl get pod cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
&& kubectl delete statefulset -l app=cassandra \
&& echo "Sleeping ${grace} seconds" 1>&2 \
&& sleep $grace \
&& kubectl delete persistentvolumeclaim -l app=cassandra
```
<!--
1. Run the following command to delete the Service you set up for Cassandra:
-->
2. 运行以下命令,删除你为 Cassandra 设置的 Service
```shell
kubectl delete service -l app=cassandra
```
<!--
## Cassandra container environment variables
The Pods in this tutorial use the [`gcr.io/google-samples/cassandra:v13`](https://github.com/kubernetes/examples/blob/master/cassandra/image/Dockerfile)
image from Google's [container registry](https://cloud.google.com/container-registry/docs/).
The Docker image above is based on [debian-base](https://github.com/kubernetes/release/tree/master/images/build/debian-base)
and includes OpenJDK 8.
This image includes a standard Cassandra installation from the Apache Debian repo.
By using environment variables you can change values that are inserted into `cassandra.yaml`.
-->
## Cassandra 容器环境变量
本教程中的 Pod 使用来自 Google [容器镜像库](https://cloud.google.com/container-registry/docs/)
的 [`gcr.io/google-samples/cassandra:v13`](https://github.com/kubernetes/examples/blob/master/cassandra/image/Dockerfile)
镜像。上面的 Docker 镜像基于 [debian-base](https://github.com/kubernetes/release/tree/master/images/build/debian-base)
并且包含 OpenJDK 8。
该映像包括来自 Apache Debian 存储库的标准 Cassandra 安装。
通过使用环境变量,你可以更改插入到 `cassandra.yaml` 中的值。
| 环境变量 | 默认值 |
| ------------------------ |:---------------: |
| `CASSANDRA_CLUSTER_NAME` | `'Test Cluster'` |
| `CASSANDRA_NUM_TOKENS` | `32` |
| `CASSANDRA_RPC_ADDRESS` | `0.0.0.0` |
## {{% heading "whatsnext" %}}
<!--
* Learn how to [Scale a StatefulSet](/docs/tasks/run-application/scale-stateful-set/).
* Learn more about the [*KubernetesSeedProvider*](https://github.com/kubernetes/examples/blob/master/cassandra/java/src/main/java/io/k8s/cassandra/KubernetesSeedProvider.java)
* See more custom [Seed Provider Configurations](https://git.k8s.io/examples/cassandra/java/README.md)
-->
* 了解如何[扩缩 StatefulSet](/docs/tasks/run-application/scale-stateful-set/)。
* 了解有关 [*KubernetesSeedProvider*](https://github.com/kubernetes/examples/blob/master/cassandra/java/src/main/java/io/k8s/cassandra/KubernetesSeedProvider.java) 的更多信息
* 查看更多自定义 [Seed Provider Configurations](https://git.k8s.io/examples/cassandra/java/README.md)
@@ -0,0 +1,461 @@
---
title: 示例:使用 Persistent Volumes 部署 WordPress 和 MySQL
content_type: tutorial
weight: 20
card:
name: tutorials
weight: 40
title: "有状态应用示例: 带持久卷的 Wordpress"
---
<!--
title: "Example: Deploying WordPress and MySQL with Persistent Volumes"
reviewers:
- ahmetb
content_type: tutorial
weight: 20
card:
name: tutorials
weight: 40
title: "Stateful Example: Wordpress with Persistent Volumes"
-->
<!-- overview -->
<!--
This tutorial shows you how to deploy a WordPress site and a MySQL database using Minikube. Both applications use PersistentVolumes and PersistentVolumeClaims to store data.
-->
本示例描述了如何通过 Minikube 在 Kubernetes 上安装 WordPress 和 MySQL。
这两个应用都使用 PersistentVolumes 和 PersistentVolumeClaims 保存数据。
<!--
A [PersistentVolume](/docs/concepts/storage/persistent-volumes/)(PV)is a piece of storage in the cluster that has been manually provisioned by an administrator, or dynamically provisioned by Kubernetes using a [StorageClass](/docs/concepts/storage/storage-classes). A [PersistentVolumeClaim](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)(PVC)is a request for storage by a user that can be fulfilled by a PV. PersistentVolumes and PersistentVolumeClaims are independent from Pod lifecycles and preserve data through restarting, rescheduling, and even deleting Pods.
-->
[PersistentVolume](/zh/docs/concepts/storage/persistent-volumes/)(PV)是一块集群里由管理员手动提供,
或 kubernetes 通过 [StorageClass](/zh/docs/concepts/storage/storage-classes) 动态创建的存储。
[PersistentVolumeClaim](/zh/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)
是用户对存储的请求,该请求可由某个 PV 来满足。
PersistentVolumes 和 PersistentVolumeClaims 独立于 Pod 生命周期而存在,
在 Pod 重启,重新调度甚至删除过程中保存数据。
{{< warning >}}
<!--
This deployment is not suitable for production use cases, as it uses single instance WordPress and MySQL Pods. Consider using [WordPress Helm Chart](https://github.com/kubernetes/charts/tree/master/stable/wordpress) to deploy WordPress in production.
-->
这种部署并不适合生产场景,它使用单实例 WordPress 和 MySQL Pods。
在生产场景中,请考虑使用 [WordPress Helm Chart](https://github.com/kubernetes/charts/tree/master/stable/wordpress)
部署 WordPress。
{{< /warning >}}
{{< note >}}
<!--
The files provided in this tutorial are using GA Deployment APIs and are specific to kubernetes version 1.9 and later. If you wish to use this tutorial with an earlier version of Kubernetes, please update the API version appropriately, or reference earlier versions of this tutorial.
-->
本教程中提供的文件使用 GA Deployment API,并且特定于 kubernetes 1.9 或更高版本。如果你希望将本教程与 Kubernetes 的早期版本一起使用,请相应地更新 API 版本,或参考本教程的早期版本。
{{< /note >}}
## {{% heading "objectives" %}}
<!--
* Create PersistentVolumeClaims and PersistentVolumes
* Create a `kustomization.yaml` with
* a Secret generator
* MySQL resource configs
* WordPress resource configs
* Apply the kustomization directory by `kubectl apply -k ./`
* Clean up
-->
* 创建 PersistentVolumeClaims 和 PersistentVolumes
* 创建 `kustomization.yaml` 使用
* Secret 生成器
* MySQL 资源配置
* WordPress 资源配置
* 应用整个 kustomization 目录 `kubectl apply -k ./`
* 清理
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
<!--
The example shown on this page works with `kubectl` 1.14 and above.
Download the following configuration files:
1. [mysql-deployment.yaml](/examples/application/wordpress/mysql-deployment.yaml)
1. [wordpress-deployment.yaml](/examples/application/wordpress/wordpress-deployment.yaml)
-->
此例在`kubectl` 1.14 或者更高版本有效。
下载下面的配置文件:
1. [mysql-deployment.yaml](/examples/application/wordpress/mysql-deployment.yaml)
2. [wordpress-deployment.yaml](/examples/application/wordpress/wordpress-deployment.yaml)
<!-- lessoncontent -->
<!--
## Create PersistentVolumeClaims and PersistentVolumes
-->
## 创建 PersistentVolumeClaims 和 PersistentVolumes
<!-- MySQL and Wordpress each require a PersistentVolume to store data. Their PersistentVolumeClaims will be created at the deployment step.
Many cluster environments have a default StorageClass installed. When a StorageClass is not specified in the PersistentVolumeClaim, the cluster's default StorageClass is used instead.
When a PersistentVolumeClaim is created, a PersistentVolume is dynamically provisioned based on the StorageClass configuration.
-->
MySQL 和 Wordpress 都需要一个 PersistentVolume 来存储数据。
他们的 PersistentVolumeClaims 将在部署步骤中创建。
许多集群环境都安装了默认的 StorageClass。如果在 PersistentVolumeClaim 中未指定 StorageClass
则使用集群的默认 StorageClass。
创建 PersistentVolumeClaim 时,将根据 StorageClass 配置动态设置 PersistentVolume。
{{< warning >}}
<!--
In local clusters, the default StorageClass uses the `hostPath` provisioner. `hostPath` volumes are only suitable for development and testing. With `hostPath` volumes, your data lives in `/tmp` on the node the Pod is scheduled onto and does not move between nodes. If a Pod dies and gets scheduled to another node in the cluster, or the node is rebooted, the data is lost.
-->
在本地集群中,默认的 StorageClass 使用`hostPath`供应器。 `hostPath`卷仅适用于开发和测试。
使用 `hostPath` 卷,你的数据位于 Pod 调度到的节点上的`/tmp`中,并且不会在节点之间移动。
如果 Pod 死亡并被调度到集群中的另一个节点,或者该节点重新启动,则数据将丢失。
{{< /warning >}}
{{< note >}}
<!--
If you are bringing up a cluster that needs to use the `hostPath` provisioner, the `--enable-hostpath-provisioner` flag must be set in the `controller-manager` component.
-->
如果要建立需要使用`hostPath`设置程序的集群,
则必须在 controller-manager 组件中设置`--enable-hostpath-provisioner`标志。
{{< /note >}}
{{< note >}}
<!-- If you have a Kubernetes cluster running on Google Kubernetes Engine, please follow [this guide](https://cloud.google.com/kubernetes-engine/docs/tutorials/persistent-disk). -->
如果你已经有运行在 Google Kubernetes Engine 的集群,
请参考[此指南](https://cloud.google.com/kubernetes-engine/docs/tutorials/persistent-disk)。
{{< /note >}}
<!--
## Create a kustomization.yaml
-->
## 创建 kustomization.yaml
<!--
### Add a Secret generator
-->
### 创建 Secret 生成器
<!--
A [Secret](/docs/concepts/configuration/secret/) is an object that stores a piece of sensitive data like a password or key. Since 1.14, `kubectl` supports the management of Kubernetes objects using a kustomization file. You can create a Secret by generators in `kustomization.yaml`.
Add a Secret generator in `kustomization.yaml` from the following command. You will need to replace `YOUR_PASSWORD` with the password you want to use.
-->
[Secret](/zh/docs/concepts/configuration/secret/) 是存储诸如密码或密钥之类的敏感数据的对象。
从 1.14 开始,`kubectl`支持使用 kustomization 文件管理 Kubernetes 对象。
你可以通过`kustomization.yaml`中的生成器创建一个 Secret。
通过以下命令在`kustomization.yaml`中添加一个 Secret 生成器。
你需要用你要使用的密码替换`YOUR_PASSWORD`
```shell
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
literals:
- password=YOUR_PASSWORD
EOF
```
<!--
## Add resource configs for MySQL and WordPress
-->
## 补充 MySQL 和 WordPress 的资源配置
<!--
The following manifest describes a single-instance MySQL Deployment. The MySQL container mounts the PersistentVolume at /var/lib/mysql. The `MYSQL_ROOT_PASSWORD` environment variable sets the database password from the Secret.
-->
以下 manifest 文件描述了单实例 MySQL 部署。MySQL 容器将 PersistentVolume 挂载在`/var/lib/mysql`
`MYSQL_ROOT_PASSWORD`环境变量设置来自 Secret 的数据库密码。
{{< codenew file="application/wordpress/mysql-deployment.yaml" >}}
<!--
The following manifest describes a single-instance WordPress Deployment. The WordPress container mounts the
PersistentVolume at `/var/www/html` for website data files. The `WORDPRESS_DB_HOST` environment variable sets
the name of the MySQL Service defined above, and WordPress will access the database by Service. The
`WORDPRESS_DB_PASSWORD` environment variable sets the database password from the Secret kustomize generated.
-->
以下 manifest 文件描述了单实例 WordPress 部署。WordPress 容器将网站数据文件位于`/var/www/html`的 PersistentVolume。`WORDPRESS_DB_HOST`环境变量集上面定义的 MySQL Service 的名称,WordPress 将通过 Service 访问数据库。`WORDPRESS_DB_PASSWORD`环境变量设置从 Secret kustomize 生成的数据库密码。
{{< codenew file="application/wordpress/wordpress-deployment.yaml" >}}
<!--
1. Download the MySQL deployment configuration file.
```shell
curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
```
2. Download the WordPress configuration file.
```shell
curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
```
3. Add them to `kustomization.yaml` file.
```shell
cat <<EOF >>./kustomization.yaml
resources:
- mysql-deployment.yaml
- wordpress-deployment.yaml
EOF
```
-->
1. 下载 MySQL deployment 配置文件。
```shell
curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
```
2. 下载 WordPress 配置文件。
```shell
curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
```
3. 补充到 `kustomization.yaml` 文件。
```shell
cat <<EOF >>./kustomization.yaml
resources:
- mysql-deployment.yaml
- wordpress-deployment.yaml
EOF
```
<!--
## Apply and Verify
-->
## 应用和验证
<!--
The `kustomization.yaml` contains all the resources for deploying a WordPress site and a
MySQL database. You can apply the directory by
```shell
kubectl apply -k ./
```
Now you can verify that all objects exist.
1. Verify that the Secret exists by running the following command:
```shell
kubectl get secrets
```
The response should be like this:
```shell
NAME TYPE DATA AGE
mysql-pass-c57bb4t7mf Opaque 1 9s
```
2. Verify that a PersistentVolume got dynamically provisioned.
```shell
kubectl get pvc
```
{{< note >}}
It can take up to a few minutes for the PVs to be provisioned and bound.
{{< /note >}}
The response should be like this:
```shell
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-8cbd7b2e-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
wp-pv-claim Bound pvc-8cd0df54-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
```
3. Verify that the Pod is running by running the following command:
```shell
kubectl get pods
```
{{< note >}}
It can take up to a few minutes for the Pod's Status to be `RUNNING`.
{{< /note >}}
The response should be like this:
```
NAME READY STATUS RESTARTS AGE
wordpress-mysql-1894417608-x5dzt 1/1 Running 0 40s
```
4. Verify that the Service is running by running the following command:
```shell
kubectl get services wordpress
```
The response should be like this:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress ClusterIP 10.0.0.89 <pending> 80:32406/TCP 4m
```
{{< note >}}
Minikube can only expose Services through `NodePort`. The EXTERNAL-IP is always pending.
{{< /note >}}
5. Run the following command to get the IP Address for the WordPress Service:
```shell
minikube service wordpress --url
```
The response should be like this:
```
http://1.2.3.4:32406
```
6. Copy the IP address, and load the page in your browser to view your site.
You should see the WordPress set up page similar to the following screenshot.
![wordpress-init](https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/WordPress.png)
-->
`kustomization.yaml`包含用于部署 WordPress 网站的所有资源以及 MySQL 数据库。你可以通过以下方式应用目录
```shell
kubectl apply -k ./
```
现在,你可以验证所有对象是否存在。
1. 通过运行以下命令验证 Secret 是否存在:
```shell
kubectl get secrets
```
响应应如下所示:
```shell
NAME TYPE DATA AGE
mysql-pass-c57bb4t7mf Opaque 1 9s
```
2. 验证是否已动态配置 PersistentVolume
```shell
kubectl get pvc
```
{{< note >}}
设置和绑定 PV 可能要花费几分钟。
{{< /note >}}
响应应如下所示:
```shell
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-8cbd7b2e-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
wp-pv-claim Bound pvc-8cd0df54-4044-11e9-b2bb-42010a800002 20Gi RWO standard 77s
```
3. 通过运行以下命令来验证 Pod 是否正在运行:
```shell
kubectl get pods
```
{{< note >}}
等待 Pod 状态变成`RUNNING`可能会花费几分钟。
{{< /note >}}
响应应如下所示:
```
NAME READY STATUS RESTARTS AGE
wordpress-mysql-1894417608-x5dzt 1/1 Running 0 40s
```
4. 通过运行以下命令来验证 Service 是否正在运行:
```shell
kubectl get services wordpress
```
响应应如下所示:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress ClusterIP 10.0.0.89 <pending> 80:32406/TCP 4m
```
{{< note >}}
Minikube 只能通过 NodePort 公开服务。EXTERNAL-IP 始终处于挂起状态
{{< /note >}}
5. 运行以下命令以获取 WordPress 服务的 IP 地址:
```shell
minikube service wordpress --url
```
响应应如下所示:
```
http://1.2.3.4:32406
```
6. 复制 IP 地址,然后将页面加载到浏览器中来查看你的站点。
你应该看到类似于以下屏幕截图的 WordPress 设置页面。
![wordpress-init](https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/WordPress.png)
{{< warning >}}
<!--
Do not leave your WordPress installation on this page. If another user finds it, they can set up a website on your instance and use it to serve malicious content. <br/><br/>Either install WordPress by creating a username and password or delete your instance.
-->
不要在此页面上保留 WordPress 安装。如果其他用户找到了它,他们可以在你的实例上建立一个网站并使用它来提供恶意内容。<br/><br/>通过创建用户名和密码来安装 WordPress 或删除你的实例。
{{< /warning >}}
## {{% heading "cleanup" %}}
<!--
1. Run the following command to delete your Secret, Deployments, Services and PersistentVolumeClaims:
```shell
kubectl delete -k ./
```
-->
1. 运行一下命令删除你的 SecretDeploymentsServices and PersistentVolumeClaims
```shell
kubectl delete -k ./
```
## {{% heading "whatsnext" %}}
<!--
* Learn more about [Introspection and Debugging](/docs/tasks/debug/debug-application/debug-running-pod/)
* Learn more about [Jobs](/docs/concepts/workloads/controllers/jobs-run-to-completion/)
* Learn more about [Port Forwarding](/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
* Learn how to [Get a Shell to a Container](/docs/tasks/debug/debug-application/get-shell-running-container/)
-->
* 进一步了解[自省与调试](/zh/docs/tasks/debug/debug-application/debug-running-pod/)
* 进一步了解 [Job](/zh/docs/concepts/workloads/controllers/jobs-run-to-completion/)
* 进一步了解[端口转发](/zh/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
* 了解如何[获得容器的 Shell](/zh/docs/tasks/debug/debug-application/get-shell-running-container/)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
---
title: "无状态应用程序"
weight: 40
---
@@ -0,0 +1,269 @@
---
title: 公开外部 IP 地址以访问集群中应用程序
content_type: tutorial
weight: 10
---
<!--
title: Exposing an External IP Address to Access an Application in a Cluster
content_type: tutorial
weight: 10
-->
<!-- overview -->
<!--
This page shows how to create a Kubernetes Service object that exposes an
external IP address.
-->
此页面显示如何创建公开外部 IP 地址的 Kubernetes 服务对象。
## {{% heading "prerequisites" %}}
<!--
* Install [kubectl](/docs/tasks/tools/).
* Use a cloud provider like Google Kubernetes Engine or Amazon Web Services to
create a Kubernetes cluster. This tutorial creates an
[external load balancer](/docs/tasks/access-application-cluster/create-external-load-balancer/),
which requires a cloud provider.
* Configure `kubectl` to communicate with your Kubernetes API server. For instructions, see the
documentation for your cloud provider.
-->
* 安装 [kubectl](/zh/docs/tasks/tools/)。
* 使用 Google Kubernetes Engine 或 Amazon Web Services 等云供应商创建 Kubernetes 集群。
本教程创建了一个[外部负载均衡器](/zh/docs/tasks/access-application-cluster/create-external-load-balancer/)
需要云供应商。
* 配置 `kubectl` 与 Kubernetes API 服务器通信。有关说明,请参阅云供应商文档。
## {{% heading "objectives" %}}
<!--
* Run five instances of a Hello World application.
* Create a Service object that exposes an external IP address.
* Use the Service object to access the running application.
-->
* 运行 Hello World 应用程序的五个实例。
* 创建一个公开外部 IP 地址的 Service 对象。
* 使用 Service 对象访问正在运行的应用程序。
<!-- lessoncontent -->
<!--
## Creating a service for an application running in five pods
-->
## 为一个在五个 pod 中运行的应用程序创建服务
<!--
1. Run a Hello World application in your cluster:
-->
1. 在集群中运行 Hello World 应用程序:
{{< codenew file="service/load-balancer-example.yaml" >}}
```shell
kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
```
<!--
The preceding command creates a
{{< glossary_tooltip text="Deployment" term_id="deployment" >}}
and an associated
{{< glossary_tooltip term_id="replica-set" text="ReplicaSet" >}}.
The ReplicaSet has five
{{< glossary_tooltip text="Pods" term_id="pod" >}}
each of which runs the Hello World application.
-->
前面的命令创建一个
{{< glossary_tooltip text="Deployment" term_id="deployment" >}}
对象和一个关联的
{{< glossary_tooltip term_id="replica-set" text="ReplicaSet" >}} 对象。
ReplicaSet 有五个 {{< glossary_tooltip text="Pods" term_id="pod" >}}
每个都运行 Hello World 应用程序。
<!--
1. Display information about the Deployment:
-->
2. 显示有关 Deployment 的信息:
```shell
kubectl get deployments hello-world
kubectl describe deployments hello-world
```
<!--
1. Display information about your ReplicaSet objects:
-->
3. 显示有关 ReplicaSet 对象的信息:
```shell
kubectl get replicasets
kubectl describe replicasets
```
<!--
1. Create a Service object that exposes the deployment:
-->
4. 创建公开 Deployment 的 Service 对象:
```shell
kubectl expose deployment hello-world --type=LoadBalancer --name=my-service
```
<!--
1. Display information about the Service:
-->
5. 显示有关 Service 的信息:
```shell
kubectl get services my-service
```
<!--
The output is similar to this:
-->
输出类似于:
```console
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.3.245.137 104.198.205.71 8080/TCP 54s
```
<!--
{{< note >}}
The `type=LoadBalancer` service is backed by external cloud providers, which is not covered in this example, please refer to [this page](/docs/concepts/services-networking/service/#loadbalancer) for the details.
{{< /note >}}
-->
提示:`type=LoadBalancer` 服务由外部云服务提供商提供支持,本例中不包含此部分,
详细信息请参考[此页](/zh/docs/concepts/services-networking/service/#loadbalancer)
<!--
{{< note >}}
If the external IP address is shown as \<pending\>, wait for a minute and enter the same command again.
{{< /note >}}
-->
提示:如果外部 IP 地址显示为 \<pending\>,请等待一分钟再次输入相同的命令。
<!--
1. Display detailed information about the Service:
-->
6. 显示有关 Service 的详细信息:
```shell
kubectl describe services my-service
```
<!--
The output is similar to this:
-->
输出类似于:
```console
Name: my-service
Namespace: default
Labels: app.kubernetes.io/name=load-balancer-example
Annotations: <none>
Selector: app.kubernetes.io/name=load-balancer-example
Type: LoadBalancer
IP: 10.3.245.137
LoadBalancer Ingress: 104.198.205.71
Port: <unset> 8080/TCP
NodePort: <unset> 32377/TCP
Endpoints: 10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 more...
Session Affinity: None
Events: <none>
```
<!--
Make a note of the external IP address (`LoadBalancer Ingress`) exposed by
your service. In this example, the external IP address is 104.198.205.71.
Also note the value of `Port` and `NodePort`. In this example, the `Port`
is 8080 and the `NodePort` is 32377.
-->
记下服务公开的外部 IP 地址(`LoadBalancer Ingress`)。
在本例中,外部 IP 地址是 104.198.205.71。还要注意 `Port``NodePort` 的值。
在本例中,`Port` 是 8080`NodePort` 是 32377。
<!--
1. In the preceding output, you can see that the service has several endpoints:
10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 more. These are internal
addresses of the pods that are running the Hello World application. To
verify these are pod addresses, enter this command:
-->
7. 在前面的输出中,你可以看到服务有几个端点:
10.0.0.6:8080、10.0.1.6:8080、10.0.1.7:8080 和另外两个,
这些都是正在运行 Hello World 应用程序的 Pod 的内部地址。
要验证这些是 Pod 地址,请输入以下命令:
```shell
kubectl get pods --output=wide
```
<!--
The output is similar to this:
-->
输出类似于:
```console
NAME ... IP NODE
hello-world-2895499144-1jaz9 ... 10.0.1.6 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-2e5uh ... 10.0.1.8 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-9m4h1 ... 10.0.0.6 gke-cluster-1-default-pool-e0b8d269-5v7a
hello-world-2895499144-o4z13 ... 10.0.1.7 gke-cluster-1-default-pool-e0b8d269-1afc
hello-world-2895499144-segjf ... 10.0.2.5 gke-cluster-1-default-pool-e0b8d269-cpuc
```
<!--
1. Use the external IP address (`LoadBalancer Ingress`) to access the Hello
World application:
-->
8. 使用外部 IP 地址(`LoadBalancer Ingress`)访问 Hello World 应用程序:
```shell
curl http://<external-ip>:<port>
```
<!--
where `<external-ip>` is the external IP address (`LoadBalancer Ingress`)
of your Service, and `<port>` is the value of `Port` in your Service
description.
If you are using minikube, typing `minikube service my-service` will
automatically open the Hello World application in a browser.
-->
其中 `<external-ip>` 是你的服务的外部 IP 地址(`LoadBalancer Ingress`),
`<port>` 是你的服务描述中的 `port` 的值。
如果你正在使用 minikube,输入 `minikube service my-service` 将在浏览器中自动打开 Hello World 应用程序。
<!--
The response to a successful request is a hello message:
-->
成功请求的响应是一条问候消息:
```shell
Hello Kubernetes!
```
## {{% heading "cleanup" %}}
<!--
To delete the Service, enter this command:
-->
要删除 Service,请输入以下命令:
```shell
kubectl delete services my-service
```
<!--
To delete the Deployment, the ReplicaSet, and the Pods that are running
the Hello World application, enter this command:
-->
要删除正在运行 Hello World 应用程序的 DeploymentReplicaSet 和 Pod,请输入以下命令:
```shell
kubectl delete deployment hello-world
```
## {{% heading "whatsnext" %}}
<!--
Learn more about
[connecting applications with services](/docs/concepts/services-networking/connect-applications-service/).
-->
进一步了解[将应用程序与服务连接](/zh/docs/concepts/services-networking/connect-applications-service/)。
@@ -0,0 +1,636 @@
---
title: "示例:使用 Redis 部署 PHP 留言板应用程序"
content_type: tutorial
weight: 20
card:
name: tutorials
weight: 30
title: "无状态应用示例:基于 Redis 的 PHP Guestbook"
min-kubernetes-server-version: v1.14
source: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
---
<!--
title: "Example: Deploying PHP Guestbook application with Redis"
reviewers:
- ahmetb
content_type: tutorial
weight: 20
card:
name: tutorials
weight: 30
title: "Stateless Example: PHP Guestbook with Redis"
min-kubernetes-server-version: v1.14
-->
<!-- overview -->
<!--
This tutorial shows you how to build and deploy a simple _(not production ready)_, multi-tier web application using Kubernetes and [Docker](https://www.docker.com/). This example consists of the following components:
-->
本教程向你展示如何使用 Kubernetes 和 [Docker](https://www.docker.com/)
构建和部署一个简单的**(非面向生产的)**多层 web 应用程序。本例由以下组件组成:
<!--
* A single-instance [Redis](https://www.redis.io/) to store guestbook entries
* Multiple web frontend instances
-->
* 单实例 [Redis](https://www.redis.io/) 以保存留言板条目
* 多个 web 前端实例
## {{% heading "objectives" %}}
<!--
* Start up a Redis leader.
* Start up two Redis followers.
* Start up the guestbook frontend.
* Expose and view the Frontend Service.
* Clean up.
-->
* 启动 Redis 领导者(Leader
* 启动两个 Redis 跟随者(Follower
* 公开并查看前端服务
* 清理
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}}
{{< version-check >}}
<!-- lessoncontent -->
<!--
## Start up the Redis Database
-->
## 启动 Redis 数据库
<!--
The guestbook application uses Redis to store its data.
-->
留言板应用程序使用 Redis 存储数据。
<!--
### Creating the Redis Deployment
-->
### 创建 Redis Deployment
<!--
The manifest file, included below, specifies a Deployment controller that runs a single replica Redis Pod.
-->
下面包含的清单文件指定了一个 Deployment 控制器,该控制器运行一个 Redis Pod 副本。
{{< codenew file="application/guestbook/redis-leader-deployment.yaml" >}}
<!--
1. Launch a terminal window in the directory you downloaded the manifest files.
1. Apply the Redis Deployment from the `redis-leader-deployment.yaml` file:
-->
1. 在下载清单文件的目录中启动终端窗口。
2. 从 `redis-leader-deployment.yaml` 文件中应用 Redis Deployment
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/redis-leader-deployment.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-deployment.yaml
```
<!--
1. Query the list of Pods to verify that the Redis Pod is running:
-->
3. 查询 Pod 列表以验证 Redis Pod 是否正在运行:
```shell
kubectl get pods
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```shell
NAME READY STATUS RESTARTS AGE
redis-leader-fb76b4755-xjr2n 1/1 Running 0 13s
```
<!--
1. Run the following command to view the logs from the Redis leader Pod:
-->
4. 运行以下命令查看 Redis Deployment 中的日志:
```shell
kubectl logs -f deployment/redis-leader
```
<!--
### Creating the Redis leader Service
-->
### 创建 Redis 领导者服务
<!--
The guestbook application needs to communicate to the Redis to write its data. You need to apply a [Service](/docs/concepts/services-networking/service/) to proxy the traffic to the Redis Pod. A Service defines a policy to access the Pods.
-->
留言板应用程序需要往 Redis 中写数据。因此,需要创建
[Service](/zh/docs/concepts/services-networking/service/) 来转发 Redis Pod
的流量。Service 定义了访问 Pod 的策略。
{{< codenew file="application/guestbook/redis-leader-service.yaml" >}}
<!--
1. Apply the Redis Service from the following `redis-leader-service.yaml` file:
-->
1. 使用下面的 `redis-leader-service.yaml` 文件创建 Redis的服务:
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/redis-leader-service.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-leader-service.yaml
```
<!--
1. Query the list of Services to verify that the Redis Service is running:
-->
2. 查询服务列表验证 Redis 服务是否正在运行:
```shell
kubectl get service
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```shell
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 1m
redis-leader ClusterIP 10.103.78.24 <none> 6379/TCP 16s
```
<!--
This manifest file creates a Service named `redis-leader` with a set of labels that match the labels previously defined, so the Service routes network traffic to the Redis Pod.
-->
{{< note >}}
这个清单文件创建了一个名为 `redis-leader` 的 Service,其中包含一组
与前面定义的标签匹配的标签,因此服务将网络流量路由到 Redis Pod 上。
{{< /note >}}
<!--
### Set up Redis followers
Although the Redis leader is a single Pod, you can make it highly available and meet traffic demands by adding a few Redis followers, or replicas.
-->
### 设置 Redis 跟随者
尽管 Redis 领导者只有一个 Pod,你可以通过添加若干 Redis 跟随者来将其配置为高可用状态,
以满足流量需求。
{{< codenew file="application/guestbook/redis-follower-deployment.yaml" >}}
<!--
1. Apply the Redis Service from the following `redis-follower-deployment.yaml` file:
-->
1. 应用下面的 `redis-follower-deployment.yaml` 文件创建 Redis Deployment
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/redis-follower-deployment.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-deployment.yaml
```
<!--
1. Verify that the two Redis follower replicas are running by querying the list of Pods:
-->
2. 通过查询 Pods 列表,验证两个 Redis 跟随者副本在运行:
```shell
kubectl get pods
```
<!--
The response should be similar to this:
-->
响应应该类似于这样:
```
NAME READY STATUS RESTARTS AGE
redis-follower-dddfbdcc9-82sfr 1/1 Running 0 37s
redis-follower-dddfbdcc9-qrt5k 1/1 Running 0 38s
redis-leader-fb76b4755-xjr2n 1/1 Running 0 11m
```
<!--
### Creating the Redis follower service
The guestbook application needs to communicate with the Redis followers to read data. To make the Redis followers discoverable, you must set up another [Service](/docs/concepts/services-networking/service/).
-->
### 创建 Redis 跟随者服务
Guestbook 应用需要与 Redis 跟随者通信以读取数据。
为了让 Redis 跟随者可被发现,你必须创建另一个
[Service](/zh/docs/concepts/services-networking/service/)。
{{< codenew file="application/guestbook/redis-follower-service.yaml" >}}
<!--
1. Apply the Redis Service from the following `redis-follower-service.yaml` file:
-->
1. 应用如下所示 `redis-follower-service.yaml` 文件中的 Redis Service
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/redis-follower-service.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-follower-service.yaml
```
<!--
1. Query the list of Services to verify that the Redis Service is running:
-->
2. 查询 Service 列表,验证 Redis 服务在运行:
```shell
kubectl get service
```
<!--
The response should be similar to this:
-->
响应应该类似于这样:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d19h
redis-follower ClusterIP 10.110.162.42 <none> 6379/TCP 9s
redis-leader ClusterIP 10.103.78.24 <none> 6379/TCP 6m10s
```
{{< note >}}
<!--
This manifest file creates a Service named `redis-follower` with a set of labels that match the labels previously defined, so the Service routes network traffic to the Redis Pod.
-->
清单文件创建了一个名为 `redis-follower` 的 Service,该 Service
具有一些与之前所定义的标签相匹配的标签,因此该 Service 能够将网络流量
路由到 Redis Pod 之上。
{{< /note >}}
<!--
## Set up and Expose the Guestbook Frontend
-->
## 设置并公开留言板前端
<!--
Now that you have the Redis storage of your guestbook up and running, start the guestbook web servers. Like the Redis followers, the frontend is deployed using a Kubernetes Deployment.
The guestbook app uses a PHP frontend. It is configured to communicate with either the Redis follower or leader Services, depending on whether the request is a read or a write. The frontend exposes a JSON interface, and serves a jQuery-Ajax-based UX.
-->
现在你有了一个为 Guestbook 应用配置的 Redis 存储处于运行状态,
接下来可以启动 Guestbook 的 Web 服务器了。
与 Redis 跟随者类似,前端也是使用 Kubernetes Deployment 来部署的。
Guestbook 应用使用 PHP 前端。该前端被配置成与后端的 Redis 跟随者或者
领导者服务通信,具体选择哪个服务取决于请求是读操作还是写操作。
前端对外暴露一个 JSON 接口,并提供基于 jQuery-Ajax 的用户体验。
<!--
### Creating the Guestbook Frontend Deployment
-->
### 创建 Guestbook 前端 Deployment
{{< codenew file="application/guestbook/frontend-deployment.yaml" >}}
<!--
1. Apply the frontend Deployment from the `frontend-deployment.yaml` file:
-->
1. 应用来自 `frontend-deployment.yaml` 文件的前端 Deployment
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-deployment.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
```
<!--
1. Query the list of Pods to verify that the three frontend replicas are running:
-->
2. 查询 Pod 列表,验证三个前端副本正在运行:
```shell
kubectl get pods -l app=guestbook -l tier=frontend
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```
NAME READY STATUS RESTARTS AGE
frontend-85595f5bf9-5tqhb 1/1 Running 0 47s
frontend-85595f5bf9-qbzwm 1/1 Running 0 47s
frontend-85595f5bf9-zchwc 1/1 Running 0 47s
```
<!--
### Creating the Frontend Service
-->
### 创建前端服务
<!--
The `Redis` Services you applied is only accessible within the Kubernetes cluster because the default type for a Service is [ClusterIP](/docs/concepts/services-networking/service/#publishing-services-service-types). `ClusterIP` provides a single IP address for the set of Pods the Service is pointing to. This IP address is accessible only within the cluster.
-->
应用的 `Redis` 服务只能在 Kubernetes 集群中访问,因为服务的默认类型是
[ClusterIP](/zh/docs/concepts/services-networking/service/#publishing-services-service-types)。
`ClusterIP` 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。
<!--
If you want guests to be able to access your guestbook, you must configure the
frontend Service to be externally visible, so a client can request the Service
from outside the Kubernetes cluster. However a Kubernetes user can use
`kubectl port-forward` to access the service even though it uses a
`ClusterIP`.
-->
如果你希望访客能够访问你的 Guestbook,你必须将前端服务配置为外部可见的,
以便客户端可以从 Kubernetes 集群之外请求服务。
然而即便使用了 `ClusterIP`Kubernetes 用户仍可以通过
`kubectl port-forward` 访问服务。
<!--
Some cloud providers, like Google Compute Engine or Google Kubernetes Engine, support external load balancers. If your cloud provider supports load balancers and you want to use it, uncomment `type: LoadBalancer`.
-->
{{< note >}}
一些云提供商,如 Google Compute Engine 或 Google Kubernetes Engine
支持外部负载均衡器。如果你的云提供商支持负载均衡器,并且你希望使用它,
只需取消注释 `type: LoadBalancer`
{{< /note >}}
{{< codenew file="application/guestbook/frontend-service.yaml" >}}
<!--
1. Apply the frontend Service from the `frontend-service.yaml` file:
-->
1. 应用来自 `frontend-service.yaml` 文件中的前端服务:
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-service.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
```
<!--
1. Query the list of Services to verify that the frontend Service is running:
-->
2. 查询 Service 列表以验证前端服务正在运行:
```shell
kubectl get services
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.97.28.230 <none> 80/TCP 19s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d19h
redis-follower ClusterIP 10.110.162.42 <none> 6379/TCP 5m48s
redis-leader ClusterIP 10.103.78.24 <none> 6379/TCP 11m
```
<!--
### Viewing the Frontend Service via `kubectl port-forward`
-->
### 通过 `kubectl port-forward` 查看前端服务
<!--
1. Run the following command to forward port `8080` on your local machine to port `80` on the service.
-->
1. 运行以下命令将本机的 `8080` 端口转发到服务的 `80` 端口。
```shell
kubectl port-forward svc/frontend 8080:80
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
```
<!--
1. load the page [http://localhost:8080](http://localhost:8080) in your browser to view your guestbook.
-->
2. 在浏览器中加载 [http://localhost:8080](http://localhost:8080)
页面以查看 Guestbook。
<!--
### Viewing the Frontend Service via `LoadBalancer`
-->
### 通过 `LoadBalancer` 查看前端服务
<!--
If you deployed the `frontend-service.yaml` manifest with type: `LoadBalancer` you need to find the IP address to view your Guestbook.
-->
如果你部署了 `frontend-service.yaml`,需要找到用来查看 Guestbook 的
IP 地址。
<!--
1. Run the following command to get the IP address for the frontend Service.
-->
1. 运行以下命令以获取前端服务的 IP 地址。
```shell
kubectl get service frontend
```
<!--
The response should be similar to this:
-->
响应应该与此类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.242.136 109.197.92.229 80:32372/TCP 1m
```
<!--
1. Copy the external IP address, and load the page in your browser to view your guestbook.
-->
2. 复制这里的外部 IP 地址,然后在浏览器中加载页面以查看留言板。
{{< note >}}
<!--
Try adding some guestbook entries by typing in a message, and clicking Submit. The message you typed appears in the frontend. This message indicates that data is successfully added to Redis through the Services you created earlier.
-->
尝试通过输入消息并点击 Submit 来添加一些留言板条目。
你所输入的消息会在前端显示。这一消息表明数据被通过你
之前所创建的 Service 添加到 Redis 存储中。
{{< /note >}}
<!--
## Scale the Web Frontend
-->
## 扩展 Web 前端
<!--
You can scale up or down as needed because your servers are defined as a Service that uses a Deployment controller.
-->
你可以根据需要执行伸缩操作,这是因为服务器本身被定义为使用一个
Deployment 控制器的 Service。
<!--
1. Run the following command to scale up the number of frontend Pods:
-->
1. 运行以下命令扩展前端 Pod 的数量:
```shell
kubectl scale deployment frontend --replicas=5
```
<!--
1. Query the list of Pods to verify the number of frontend Pods running:
-->
2. 查询 Pod 列表验证正在运行的前端 Pod 的数量:
```shell
kubectl get pods
```
<!--
The response should look similar to this:
-->
响应应该类似于这样:
```
NAME READY STATUS RESTARTS AGE
frontend-85595f5bf9-5df5m 1/1 Running 0 83s
frontend-85595f5bf9-7zmg5 1/1 Running 0 83s
frontend-85595f5bf9-cpskg 1/1 Running 0 15m
frontend-85595f5bf9-l2l54 1/1 Running 0 14m
frontend-85595f5bf9-l9c8z 1/1 Running 0 14m
redis-follower-dddfbdcc9-82sfr 1/1 Running 0 97m
redis-follower-dddfbdcc9-qrt5k 1/1 Running 0 97m
redis-leader-fb76b4755-xjr2n 1/1 Running 0 108m
```
<!--
1. Run the following command to scale down the number of frontend Pods:
-->
3. 运行以下命令缩小前端 Pod 的数量:
```shell
kubectl scale deployment frontend --replicas=2
```
<!--
1. Query the list of Pods to verify the number of frontend Pods running:
-->
4. 查询 Pod 列表验证正在运行的前端 Pod 的数量:
```shell
kubectl get pods
```
<!--
The response should look similar to this:
-->
响应应该类似于这样:
```
NAME READY STATUS RESTARTS AGE
frontend-85595f5bf9-cpskg 1/1 Running 0 16m
frontend-85595f5bf9-l9c8z 1/1 Running 0 15m
redis-follower-dddfbdcc9-82sfr 1/1 Running 0 98m
redis-follower-dddfbdcc9-qrt5k 1/1 Running 0 98m
redis-leader-fb76b4755-xjr2n 1/1 Running 0 109m
```
## {{% heading "cleanup" %}}
<!--
Deleting the Deployments and Services also deletes any running Pods. Use labels to delete multiple resources with one command.
-->
删除 Deployments 和服务还会删除正在运行的 Pod。
使用标签用一个命令删除多个资源。
<!--
1. Run the following commands to delete all Pods, Deployments, and Services.
-->
1. 运行以下命令以删除所有 PodDeployments 和 Services。
```shell
kubectl delete deployment -l app=redis
kubectl delete service -l app=redis
kubectl delete deployment frontend
kubectl delete service frontend
```
<!--
The responses should be:
-->
响应应该是:
```
deployment.apps "redis-follower" deleted
deployment.apps "redis-leader" deleted
deployment.apps "frontend" deleted
service "frontend" deleted
```
<!--
1. Query the list of Pods to verify that no Pods are running:
-->
2. 查询 Pod 列表,确认没有 Pod 在运行:
```shell
kubectl get pods
```
<!--
The response should be this:
-->
响应应该是:
```
No resources found in default namespace.
```
## {{% heading "whatsnext" %}}
<!--
* Complete the [Kubernetes Basics](/docs/tutorials/kubernetes-basics/) Interactive Tutorials
* Use Kubernetes to create a blog using [Persistent Volumes for MySQL and Wordpress](/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/#visit-your-new-wordpress-blog)
* Read more about [connecting applications](/docs/concepts/services-networking/connect-applications-service/)
* Read more about [Managing Resources](/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively)
-->
* 完成 [Kubernetes 基础](/zh/docs/tutorials/kubernetes-basics/) 交互式教程
* 使用 Kubernetes 创建一个博客,使用
[MySQL 和 Wordpress 的持久卷](/zh/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/#visit-your-new-wordpress-blog)
* 进一步阅读[连接应用程序](/zh/docs/concepts/services-networking/connect-applications-service/)
* 进一步阅读[管理资源](/zh/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively)