Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
@@ -0,0 +1,127 @@
|
||||
---
|
||||
approvers:
|
||||
- eparis
|
||||
- pmorie
|
||||
title: 使用ConfigMap来配置Redis
|
||||
content_template: templates/tutorial
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
这篇文档基于[使用ConfigMap来配置Containers](/docs/tasks/configure-pod-container/configure-pod-configmap/) 这个任务,提供了一个使用ConfigMap来配置Redis的真实案例。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture objectives %}}
|
||||
|
||||
* 创建一个ConfigMap。
|
||||
* 使用ConfigMap来配置pod参数。
|
||||
* 创建pod。
|
||||
* 验证是否配置成功。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
* 理解[使用ConfigMap来配置Containers](/docs/tasks/configure-pod-container/configure-pod-configmap/)。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture lessoncontent %}}
|
||||
|
||||
|
||||
## 真实世界的案例:使用ConfigMap来配置Redis
|
||||
|
||||
按照下面的步骤,您可以使用ConfigMap中的数据来配置Redis缓存。
|
||||
|
||||
1. 根据`docs/user-guide/configmap/redis/redis-config`来创建一个ConfigMap:
|
||||
|
||||
```shell
|
||||
kubectl create configmap example-redis-config --from-file=docs/user-guide/configmap/redis/redis-config
|
||||
|
||||
kubectl get configmap example-redis-config -o yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
redis-config: |
|
||||
maxmemory 2mb
|
||||
maxmemory-policy allkeys-lru
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
creationTimestamp: 2016-03-30T18:14:41Z
|
||||
name: example-redis-config
|
||||
namespace: default
|
||||
resourceVersion: "24686"
|
||||
selfLink: /api/v1/namespaces/default/configmaps/example-redis-config
|
||||
uid: 460a2b6e-f6a3-11e5-8ae5-42010af00002
|
||||
```
|
||||
|
||||
1. 使用ConfigMap来配置pod参数:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: kubernetes/redis:v1
|
||||
env:
|
||||
- name: MASTER
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
resources:
|
||||
limits:
|
||||
cpu: "0.1"
|
||||
volumeMounts:
|
||||
- mountPath: /redis-master-data
|
||||
name: data
|
||||
- mountPath: /redis-master
|
||||
name: config
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
- name: config
|
||||
configMap:
|
||||
name: example-redis-config
|
||||
items:
|
||||
- key: redis-config
|
||||
path: redis.conf
|
||||
```
|
||||
1. 创建pod:
|
||||
|
||||
```shell
|
||||
kubectl create -f docs/user-guide/configmap/redis/redis-pod.yaml
|
||||
```
|
||||
|
||||
In the example, the config volume is mounted at `/redis-master`.
|
||||
It uses `path` to add the `redis-config` key to a file named `redis.conf`.
|
||||
The file path for the redis config, therefore, is `/redis-master/redis.conf`.
|
||||
This is where the image will look for the config file for the redis master.
|
||||
|
||||
1. 使用`kubectl exec`命令进入pod后运行 `redis-cli` 工具来验证配置是否成功:
|
||||
|
||||
```shell
|
||||
kubectl exec -it redis redis-cli
|
||||
127.0.0.1:6379> CONFIG GET maxmemory
|
||||
1) "maxmemory"
|
||||
2) "2097152"
|
||||
127.0.0.1:6379> CONFIG GET maxmemory-policy
|
||||
1) "maxmemory-policy"
|
||||
2) "allkeys-lru"
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 了解关于[ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/)的更多知识。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: 概述
|
||||
linkTitle: Try Our Interactive Tutorials
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="./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 帮助您确保这些容器化的应用程序在您想要的时间和地点运行,并帮助应用程序找到它们需要的资源和工具。 <a href="http://kubernetes.io/docs/whatisk8s/">Kubernetes</a> 是一个可用于生产的开源平台,根据 Google 容器集群方面积累的经验,以及来自社区的最佳实践而设计。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="basics-modules" class="content__modules">
|
||||
<h2>Kubernetes 基础模块</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/cluster-intro/"><img src="./public/images/module_01.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="cluster-intro/"><h5>1. 创建一个 Kubernetes 集群</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/deploy-intro/"><img src="./public/images/module_02.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="deploy-intro/"><h5>2. 部署应用程序</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/explore-intro/"><img src="./public/images/module_03.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="explore-intro/"><h5>3. 应用程序探索</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/expose-intro/"><img src="./public/images/module_04.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="expose-intro/"><h5>4. 应用外部可见</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/scale-intro/"><img src="./public/images/module_05.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="scale-intro/"><h5>5. 应用可扩展</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/update-intro/"><img src="./public/images/module_06.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="update-intro/"><h5>6. 应用更新</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/cluster-intro/" role="button">开始教程<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: 互动教程 - 创建集群
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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-font="Roboto" data-katacoda-fontheader="Roboto Slab" 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-intro/" role="button">Continue to Module 2<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: 使用 Minikube 创建一个集群
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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 是一个 <a href="https://github.com/kubernetes/kubernetes">开源</a> 平台,可满足生产环境的需要。
|
||||
</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>节点 是 Kubernetes 集群中的工作机器,可以是物理机或虚拟机。</b> 每个工作节点都有一个 Kubelet,它是管理 节点 并与 Kubernetes Master 节点进行通信的代理。节点 上还应具有处理容器操作的工作,例如 <a href="https://www.docker.com/">Docker</a> 或 <a href="https://coreos.com/rkt/">rkt</a>。一个 Kubernetes 工作集群至少有三个节点。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> Master 管理集群,而 节点 用于托管正在运行的应用程序。 </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>当您在 Kubernetes 上部署应用程序时,您可以告诉 master 启动应用程序容器。Master 调度容器在集群的 节点 上运行。<b> 节点 使用 Master 公开的 Kubernetes API 与 Master 通信</b>。最终用户还可以直接使用 Kubernetes 的 API 与集群交互。</p>
|
||||
|
||||
<p>Kubernetes 集群可以部署在物理机或虚拟机上。要开始使用 Kubernetes 开发,您可以使用 <a href="https://github.com/kubernetes/minikube">Minikube</a>。Minikube 是一个轻量级的 Kubernetes 实现,会在本机创建一台虚拟机,并部署一个只包含一个节点的简单集群。 Minikube 适用于 Linux, Mac OS 和 Windows 系统。Minikube CLI 提供了集群的基本引导操作,包括启动、停止、状态和删除。为了完成此基础训练,您将使用预先安装了 Minikube 的在线终端。</p>
|
||||
|
||||
<p>现在您已经知道 Kubernetes 是什么,让我们使用在线教程,开始我们的第一个集群!</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a class="btn btn-lg btn-success" href="/docs/tutorials/kubernetes-basics/cluster-interactive/" role="button">启动互动教程 <span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: 互动教程 - 部署应用程序
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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__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-font="Roboto" data-katacoda-fontheader="Roboto Slab" 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-intro/" role="button">Continue to Module 3<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: 使用 kubectl 创建部署
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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>了解应用程序部署</li>
|
||||
<li>使用 kubectl 在 Kubernetes 上部署您的第一个应用程序</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Kubernetes 部署</h3>
|
||||
<p>
|
||||
一旦运行了 Kubernetes 集群,您可以在其上部署容器化应用程序。为此,您可以创建一个 Kubernetes <b>Deployment</b>。Deployment 负责创建和更新应用程序实例。创建 Deployment 后, Kubernetes master 会将 Deployment 创建的应用程序实例调度到集群中的各个节点。
|
||||
</p>
|
||||
|
||||
<p>创建应用程序实例后,Kubernetes 部署控制器会持续监视这些实例。如果托管它的节点不可用或删除,则部署控制器将替换实例。 <b>这提供了一种解决机器故障或维护的自愈机制。</b></p>
|
||||
|
||||
<p>在编排诞生前的世界中,通常会使用安装脚本启动应用程序,但是它们并不能从机器故障中恢复。通过创建应用程序实例并使其运行在跨节点的机器之间,Kubernetes 部署提供了截然不同的应用管理方法。 </p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>概要:</h3>
|
||||
<ul>
|
||||
<li>部署</li>
|
||||
<li>Kubectl</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>
|
||||
部署负责创建和更新应用程序的实例
|
||||
</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<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>您可以使用 Kubernetes 命令行工具 <b>Kubectl</b>创建和管理部署。Kubectl 使用 Kubernetes API 与集群进行交互。在本模块中,您将学习在 Kubernetes 集群上运行应用程序部署所需的最常见的 Kubectl 命令。</p>
|
||||
|
||||
<p>创建部署时,您需要为应用程序指定容器镜像以及要运行的副本数。您可以稍后通过更新部署来更改该信息;基础训练模块 <a href="/docs/tutorials/kubernetes-basics/scale-intro/">5</a> 和 <a href="/docs/tutorials/kubernetes-basics/update-intro/">6</a> 讨论如何扩展和更新您的部署。</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> 应用程序需要打包成支持的容器格式之一,以便部署在 Kubernetes 上。</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>对于我们的第一个部署,我们将使用 <a href="https://nodejs.org">Node.js</a> 应用程序打包到 Docker 容器。源代码和 Dockerfile 可在 Kubernetes Bootcamp 的 <a href="https://github.com/kubernetes/kubernetes-bootcamp">GitHub 存储库</a> 中找到。</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/deploy-interactive/" role="button">启动互动教程 <span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: 互动教程 - 应用程序探索
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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__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-font="Roboto" data-katacoda-fontheader="Roboto Slab" 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/expose-intro/" role="button">Continue to Module 4<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: 查看 Pods 和节点
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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 Pods</li>
|
||||
<li>了解 Kubernetes Nodes</li>
|
||||
<li>已部署应用的故障排除</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h2>Kubernetes Pods</h2>
|
||||
<p>当您在模块 <a href="/docs/tutorials/kubernetes-basics/deploy-intro/">2</a>中创建部署时,Kubernetes 创建了一个 <b>Pod</b> 来托管您的应用程序实例。Pod 是一个 Kubernetes 的资源抽象,表示一个或多个应用容器 (例如 Docker 或 rkt) 组,以及一些用于这些容器的共享资源。这些资源包括:</p>
|
||||
<ul>
|
||||
<li>共享存储,如卷</li>
|
||||
<li>网络,作为唯一的集群 IP 地址</li>
|
||||
<li>每个容器如何运行的信息,例如容器镜像版本或要使用的特定端口</li>
|
||||
</ul>
|
||||
<p>Pod 模型可以理解为应用程序特定的 "逻辑主机",并且可以包含相对紧密耦合的不同应用程序容器。例如,Pod 可能包含带有 Node.js 应用程序的容器以及另一个要吸收 Node.js Web 服务器提供的数据的不同容器。Pod 中的容器共享 IP 地址和端口空间,始终位于同一位置并且统一调度,并在相同的节点上运行,共享上下文环境。</p>
|
||||
|
||||
<p>Pods 是 Kubernetes 平台上原子级别的单元。当我们在 Kubernetes 上创建一个部署时,该部署将在其中创建包含容器的 Pod (而不是直接创建容器)。每个 Pod 都绑定到它被调度的节点,并且始终在那里,直到终止 (根据重启策略) 或删除。在节点故障的情况下,在集群中的其他可用节点上调度相同的 Pod。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>概要:</h3>
|
||||
<ul>
|
||||
<li>Pods</li>
|
||||
<li>节点</li>
|
||||
<li>Kubectl 主要命令</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>
|
||||
Pod是由一个或者多个应用程序容器构成的(例如 Docker 或 rkt),包含共享存储 (卷),IP 地址以及有关如何运行它们的信息。
|
||||
</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Pods 概览</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>节点</h2>
|
||||
<p>Pod 总是运行在 <b>Node</b>上。Node 是 Kubernetes 的工作机器,可以是虚拟机或物理机,这取决于在集群的安装情况。每个节点由 Master 管理。一个节点上可以有多个 Pod, Kubernetes master 会自动处理调度集群各个节点上的 Pod。 Master 在自动调度时,会考虑每个 Node 上的可用资源。</p>
|
||||
|
||||
<p>每个 Kubernetes 节点至少运行以下组件:</p>
|
||||
<ul>
|
||||
<li>Kubelet 是负责 Kubernetes Master 和 所有节点之间通信的进程,它管理机器上运行的 Pod 和容器。</li>
|
||||
<li>容器运行时(例如 Docker, rkt) 负责从镜像仓库中拉取容器镜像,解包容器并运行应用程序。</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> 如果一些容器属于强耦合并且需要共享资源(例如 磁盘),那么这些容器应该放到单个 Pod 中一起调度。 </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_03_nodes.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2>使用 kubectl 进行故障排除</h2>
|
||||
<p>在模块 <a href="/docs/tutorials/kubernetes-basics/deploy-intro/">2</a>中,您使用了 Kubectl 命令行接口。您将在模块 3 中继续使用它来获取有关已部署应用程序及其环境的信息。最常见的操作可以通过以下 kubectl 命令完成:</p>
|
||||
<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>您可以使用这些命令来查看应用程序部署的时间,它们当前的状态,运行的位置及其配置。</p>
|
||||
|
||||
<p>现在我们更多地了解了集群组件和命令行交互,接下来,一起来探索分析我们的应用程序。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> 节点是 Kubernetes 中的工作机器,可能是物理机或虚拟机,具体取决于集群的安装配置。多个 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-interactive/" role="button">启动互动教程<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: 互动教程 - 应用外部可见
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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-font="Roboto" data-katacoda-fontheader="Roboto Slab" 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/scale-intro/" role="button">Continue to Module 5<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: 使用服务发布您的应用程序
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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>了解标签和标签选择器对象如何与服务相关联</li>
|
||||
<li>通过 Service 在 Kubernetes 集群外发布应用程序</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Kubernetes 服务概述</h3>
|
||||
|
||||
<p>Kubernetes <a href="/docs/concepts/workloads/pods/pod-overview/">Pods</a> 终有一死。
|
||||
Pods 实际上有一个 <a href="/docs/concepts/workloads/pods/pod-lifecycle/">生命周期</a>。
|
||||
当工作节点死机时,节点上运行的Pod也将丢失。
|
||||
一个 <a href="/docs/user-guide/replication-controller/#what-is-a-replicationcontroller">ReplicationController</a> 可能会通过创建新的Pod以动态地将集群恢复到所需的状态,以保持您的应用程序运行。
|
||||
比如说,假如一个图像处理软件有三个副本。这些副本是可替代的,前端系统不应关心后端副本,即使Pod丢失并重建也不会更改。
|
||||
也就是说,Kubernetes 集群中的每个 Pod 都有一个唯一的IP地址,即使在同一个节点上的 Pods 也是如此,所以此时就需要一种自动调整更改 Pod 的方法,以便您的应用程序继续运行。</p>
|
||||
<p><i>服务</i>:Kubernetes 中的服务是一个抽象对象,它定义了一组逻辑的 Pods 和一个访问它们的策略。 服务让互相依赖的 Pod 之间的耦合松动。 服务像所有 Kubernetes 对象一样,由 YAML <a href="/docs/concepts/configuration/overview/#general-config-tips">(首选)</a> 或 JSON 定义。
|
||||
针对服务的一组 Pod 通常由 <i>LabelSelector</i> 确定(参见下文,为什么您可能不希望将 <code>选择器</code> 包含在规范中)。</p>
|
||||
|
||||
<p>虽然每个 Pod 都有一个唯一的 IP 地址,但是这些 IP 不会在没有服务的情况下公开在群集之外。服务允许您的应用程序接收流量。 可以通过在 ServiceSpec 中指定<code>类型</code> 以不同方式显示服务:</p>
|
||||
<ul>
|
||||
<li><i>ClusterIP</i>(默认) - 在集群中的内部IP上公开服务。此类型使服务只能从集群中访问。</li>
|
||||
<li><i>NodePort</i> —— 使用NAT在群集中每个选定的节点的同一端口上显示该服务。使用 <code><NodeIP>:<NodePort></code>可以从群集外部访问服务。建立 ClusterIP 的超集。</li>
|
||||
<li><i>LoadBalancer</i> —— 在当前云中创建外部负载平衡器(如果支持),并为服务分配固定的外部IP。建立 NodePort 的超集。</li>
|
||||
<li><i>ExternalName</i> —— 使用任意名称显示该服务(由规范中的<code>externalName</code> 指定),本过程通过使用该名称返回 CNAME 记录达成。无须使用代理。这种类型需要 v1.7 或更高版本的 <code>kube-dns</code>.</li>
|
||||
</ul>
|
||||
<p>有关不同类型服务的详细信息,请参见 <a href="/docs/tutorials/services/source-ip/">使用源IP</a> 教程。另请参阅 <a href="/docs/concepts/services-networking/connect-applications-service">使用服务连接应用程序</a>.</p>
|
||||
<p>另外,请注意,服务中有一些使用案例涉及在规范中不定义<code>选择器</code> 。不使用 <code>选择器</code> 创建的服务也不会创建相应的端点对象。 这允许用户手动将服务映射到特定端点。没有选择器还有可能是因为您严格地使用了 <code>type: ExternalName</code>.</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>摘要</h3>
|
||||
<ul>
|
||||
<li>对外部流量曝光 Pod </li>
|
||||
<li>跨多个 Pods 进行流量负载均衡</li>
|
||||
<li>使用标签</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>Kubernetes 服务是一个抽象层,它定义了一组逻辑的Pods,并为这些Pods启用了外部流量曝光、负载平衡和服务发现。</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h3>服务和标签</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服务可以跨一组 Pod 路由流量。服务是允许 Pod 在 Kubernetes 中死亡和复制而不影响应用程序的抽象层。相关 Pod 之间的发现和路由(如应用程序中的前端和后端组件)是由 Kubernetes Services 处理的。</p>
|
||||
<p> 服务使用 <a href="/docs/concepts/overview/working-with-objects/labels">标签和选择器</a>,匹配一组 Pod,成为分组原语,此原语允许在 Kubernetes 中的对象进行逻辑运算。
|
||||
标签是一对附加到对象的键/值对,可以以多种方式使用,方式如下: </p>
|
||||
<ul>
|
||||
<li>指定用于开发、测试和生产的对象</li>
|
||||
<li>嵌入版本标签</li>
|
||||
<li>使用标签分类对象</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>您可以在使用<br><code>--expose</code> 在 kubectl 中创建部署的同时创建服务。</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>标签可以在创建时或之后附加到对象后,并支持随时修改。让我们现在开始使用服务公开我们的应用程序并应用一些标签吧。</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-interactive/" role="button">启动互动教程<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: 互动教程 - 扩展您的应用程序
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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-font="Roboto" data-katacoda-fontheader="Roboto Slab" 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/update-intro/" role="button">Continue to Module 6<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<a class="scrolltop" href="#top"></a>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: 运行应用程序的多个实例
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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>使用 kubectl 伸缩应用程序</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>应用程序伸缩</h3>
|
||||
|
||||
<p>在之前的模块中,我们创建了一个 <a href="http://kubernetes.io/docs/user-guide/deployments/"> Deployment</a>,然后通过 <a href="http://kubernetes.io/docs/user-guide/services/">Service</a>让应用程序外部可见。
|
||||
Deployment 仅为我们的应用程序创建了一个 Pod。
|
||||
当流量增加时,我们将需要扩展应用程序以跟上用户需求。</p>
|
||||
|
||||
<p><b>Scaling</b> 是通过更改 Deployment 中的副本数量实现的。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>摘要:</h3>
|
||||
<ul>
|
||||
<li>Deployment 的伸缩</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<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 概述</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 active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling1.svg">
|
||||
</div>
|
||||
|
||||
<div class="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>扩展 Deployment 将确保创建新的 Pods 并将其调度到拥有可用资源的 Node 节点上,收缩会保证 Pods 数量减少至新的所需状态。
|
||||
Kubernetes 还支持 Pods 的 <a href="http://kubernetes.io/docs/user-guide/horizontal-pod-autoscaling/"> 自动缩放 </a> ,但不在本教程范围之内。收缩到零也是可以的,此时它将终止指定 Deployment 的所有 Pod。 </p>
|
||||
|
||||
<p>运行应用程序的多个实例需要一种将流量分发给所有实例的方法。服务有内置的负载均衡器,可将网络流量分配给 Deployment 暴露的所有 Pods。服务通过使用 endpoints 持续监控运行的 Pods,以确保流量仅发送到可用的 Pods。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>通过更改 Deployment 中的副本数可以实现伸缩应用程序。</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<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-interactive/" role="button">启动互动教程 <span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: 互动教程 - 更新您的应用程序
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<link href="/docs/tutorials/kubernetes-basics/public/css/styles.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/6" data-katacoda-color="326de6" data-katacoda-secondary="273d6d" data-katacoda-hideintro="false" data-katacoda-font="Roboto" data-katacoda-fontheader="Roboto Slab" data-katacoda-prompt="Kubernetes Bootcamp Terminal" style="height: 600px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
title: 执行滚动更新
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<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>使用 kubectl 执行滚动更新</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>更新应用程序</h3>
|
||||
|
||||
<p>用户期望应用程序始终可用,并且希望开发人员每天部署新版本。在 Kubernetes 上这通过滚动更新(Rolling updates)达成。 <b>Rolling updates</b> 允许通过使用新的 Pods 实例逐个更新来实现零停机的部署更新。新的 Pods 会被调度到可用资源的 Node 节点上。</p>
|
||||
|
||||
<p>在上一个模块中,我们将应用程序扩展为运行多个实例。这也是执行更新但不影响应用可用性所需的条件。默认情况下,更新期间最大数量的不可用 Pod 以及最大数量的新 Pod 是一。 这两个选项可以配置为数字或百分比(Pods)。
|
||||
在 Kubernetes 中,更新已版本化,任何部署更新都可以恢复到以前的 (稳定) 版本。</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>摘要:</h3>
|
||||
<ul>
|
||||
<li>更新应用程序</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>滚动更新允许通过使用新的 Pods 实例逐个更新来实现零停机的部署更新。 </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-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 active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates1.svg" >
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates2.svg">
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates3.svg">
|
||||
</div>
|
||||
|
||||
<div class="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>与应用程序伸缩类似,如果 Deployment 外部可见,则服务将在更新期间将流量负载均衡到可用的 Pod。可用的 Pod 指的是应用程序用户可用的实例。</p>
|
||||
|
||||
<p>滚动更新允许以下操作:</p>
|
||||
<ul>
|
||||
<li>将应用程序从一个环境升级到另一个环境 (通过容器镜像更新)</li>
|
||||
<li>回滚到以前的版本</li>
|
||||
<li>持续集成和持续交付,实现应用程序零停机</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>如果部署外部可见,则服务将在更新期间将流量负载均衡到可用的 Pod。 </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<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-interactive/" role="button">启动交互式教程<span class="btn__next">›</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
---
|
||||
title: 使用命令式的方式管理 Kubernetes 对象
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
直接使用内置的 `kubectl` 命令行工具,以命令式方式可以快速创建,更新和删除 Kubernetes 对象。本文档介绍了这些命令是如何组织的,以及如何使用它们来管理活动对象。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 权衡
|
||||
|
||||
`kubectl` 工具支持三种方式进行对象的管理:
|
||||
|
||||
* 命令式的方式
|
||||
* 命令式的对象配置
|
||||
* 声明式的对象配置
|
||||
|
||||
参见[Kubernetes对象管理](/docs/concepts/tools/kubectl/object-management-overview/)
|
||||
讨论各种对象管理方式的优缺点.
|
||||
|
||||
## 如何创建对象
|
||||
|
||||
`kubectl` 工具支持用于创建一些最常用的对象类型的动词驱动命令,这些命令的命名让不熟悉Kubernetes 对象的用户也可以见名知义。
|
||||
|
||||
- `run`: 创建一个新的 Deployment 对象以在一个或多个 Pod 中运行 Containers。
|
||||
- `expose`: 创建一个新的 Service 对象用于负载均衡 Pods 上的的网络流量。
|
||||
- `autoscale`: 创建一个新的 Autoscaler 对象,来实现 Deployment 等控制器的自动水平拓展。
|
||||
|
||||
`kubectl` 工具也支持由对象类型驱动的创建命令。 这些命令支持更多的对象类型,并且对其意图更为明确,但要求用户知道他们打算创建的对象的类型。
|
||||
|
||||
- `create <objecttype> [<subtype>] <instancename>`
|
||||
|
||||
某些对象类型具有您可以在“create"命令中指定的子类型。例如,Service对象有ClusterIP,LoadBalancer和NodePort等几种子类型。以下是使用子类型NodePort创建一个服务的示例:
|
||||
|
||||
```shell
|
||||
kubectl create service nodeport <myservicename>
|
||||
```
|
||||
|
||||
在前面的例子中, `create service nodeport`命令叫做 `create service`命令的子命令.
|
||||
|
||||
您可以使用 `-h` 标志来查找子命令支持的参数和标志:
|
||||
|
||||
```shell
|
||||
kubectl create service nodeport -h
|
||||
```
|
||||
|
||||
## 如何更新对象
|
||||
|
||||
`kubectl` 命令支持一些常见更新操作的动词驱动命令。这些命令的命名方式可以让不熟悉 Kubernetes 对象的用户,在不知道必须设置的特定字段的情况下也可以执行更新操作:
|
||||
|
||||
- `scale`: 通过更新控制器的副本数量,水平扩展控制器以添加或删除 Pod。
|
||||
- `annotate`: 从对象添加或删除注释。
|
||||
- `label`: 为对象添加或删除标签。
|
||||
|
||||
`kubectl`命令还支持由对象的一个切面驱动的更新命令.设置此切面可能会为不同的对象类型设置不同的字段:
|
||||
|
||||
- `set` <field>: 设置对象的一个切面。
|
||||
|
||||
**注**: 在 Kubernetes 版本 1.5 中,并不是每个动词驱动的命令都有一个相关的切面驱动的命令。
|
||||
|
||||
`kubectl` 工具支持直接更新活动对象的其他方法,然而,它们需要更好的了解 Kubernetes 对象模式。
|
||||
|
||||
- `edit`: 通过在编辑器中打开其配置,直接编辑活动对象的原始配置。
|
||||
- `patch`: 通过使用补丁字符串直接修改活动对象的特定字段。
|
||||
|
||||
有关补丁字符串的更多详细信息,请参阅补丁部分
|
||||
[API 公约](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#patch-operations)。
|
||||
|
||||
## 如何删除对象
|
||||
|
||||
您可以使用 `delete` 命令从集群中删除一个对象:
|
||||
|
||||
- `delete <type>/<name>`
|
||||
|
||||
**注意**: 您可以对命令式命令和命令式对象配置都使用 `kubectl delete` 方法。两者的差异在于传递的命令参数不同。要将
|
||||
`kubectl delete` 作为命令式命令使用,需将要删除的对象作为参数传递。以下是传递名为 nginx 的 Deployment 对象的示例:
|
||||
|
||||
```shell
|
||||
kubectl delete deployment/nginx
|
||||
```
|
||||
|
||||
## 如何查看对象
|
||||
|
||||
{{< comment >}}
|
||||
TODO(pwittrock): 实现时取消注释。
|
||||
|
||||
您可以使用 `kubectl view` 打印对象的指定字段。
|
||||
|
||||
- `view`: 打印对象的特定字段的值。
|
||||
|
||||
{{< /comment >}}
|
||||
|
||||
|
||||
|
||||
有几个命令用于打印有关对象的信息:
|
||||
|
||||
- `get`: 打印有关匹配对象的基本信息。使用 `get -h` 来查看选项列表。
|
||||
- `describe`: 打印有关匹配对象的聚合详细信息。
|
||||
- `logs`: 打印 Pod 运行容器的 stdout 和 stderr 信息。
|
||||
|
||||
## 使用 `set` 命令在创建之前修改对象
|
||||
|
||||
有一些对象字段没有可以在 `create` 命令中使用的标志。在某些情况下,您可以组合使用 `set` 和 `create` 在对象创建之前指定字段的值。这是通过将 `create` 命令的输出管道连接到 `set` 命令,然后回到 `create` 命令。以下是一个例子:
|
||||
|
||||
```sh
|
||||
kubectl create service clusterip <myservicename> -o yaml --dry-run | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -
|
||||
```
|
||||
|
||||
1. 使用 `create service -o yaml --dry-run` 创建服务配置,并将其作为 YAML 打印到 stdout,而不是将其发送到 Kubernetes API 服务器。
|
||||
1. 使用 `set --local -f - -o yaml` 从 stdin 读取配置,并将更新后的配置作为 YAML 写入 stdout。
|
||||
1. 使用 `kubectl create -f -` 从 stdin 提供的配置创建对象。
|
||||
|
||||
## 使用 `--edit` 在创建之前修改对象
|
||||
|
||||
您可以使用 `kubectl create --edit` 命令在对象创建之前,对对象进行任意更改。以下是一个例子:
|
||||
|
||||
```sh
|
||||
kubectl create service clusterip my-svc -o yaml --dry-run > /tmp/srv.yaml
|
||||
kubectl create --edit -f /tmp/srv.yaml
|
||||
```
|
||||
|
||||
1. 使用`create service` 创建服务的配置并将其保存到 `/tmp/srv.yaml`。
|
||||
1. 使用`create --edit` 在创建对象之前打开配置文件进行编辑。
|
||||
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
- [使用对象配置管理 Kubernetes 对象(必要)](/docs/tutorials/object-management-kubectl/imperative-object-management-configuration/)
|
||||
- [使用对象配置(声明式)管理 Kubernetes 对象](/docs/tutorials/object-management-kubectl/declarative-object-management-configuration/)
|
||||
- [Kubectl 命令参考](/docs/user-guide/kubectl/v1.6/)
|
||||
- [Kubernetes 对象模式参考](/docs/resources-reference/v1.6/)
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
title: Kubernetes 对象管理
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
`kubectl` 命令行工具支持 Kubernetes 对象几种不同的创建和管理方法。本文档简要介绍了这些方法.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 管理技巧
|
||||
|
||||
**警告:** Kubernetes 对象应该只使用一种技术进行管理。混合使用不同的技术,会导致相同对象出现未定义的行为。
|
||||
|
||||
| 管理技术 | 操作 |推荐环境 | 支持撰写 | 学习曲线 |
|
||||
|----------------------------------|----------------------|------------------------|--------------------|----------------|
|
||||
| 命令式的方式 | 活动对象 | 开发项目 | 1+ | 最低 |
|
||||
| 命令式对象配置 | 单文件 | 生产项目 | 1 | 中等 |
|
||||
| 声明式对象配置 | 文件目录 | 生产项目 | 1+ | 最高 |
|
||||
|
||||
## 命令式的方式
|
||||
|
||||
当使用命令式的命令时,用户直接对集群中的活动对象进行操作。用户提供 `kubectl` 命令的参数或标记进行操作。
|
||||
|
||||
这是在集群中启动或运行一次性任务的最简单的方法。因为这种技术直接在活动对象上运行,所以它没有提供以前配置的历史记录。
|
||||
|
||||
### 例子
|
||||
|
||||
通过创建 Deployment 对象来运行 nginx 容器的实例:
|
||||
|
||||
```sh
|
||||
kubectl run nginx --image nginx
|
||||
```
|
||||
|
||||
使用不同的语法做同样的事情:
|
||||
|
||||
```sh
|
||||
kubectl create deployment nginx --image nginx
|
||||
```
|
||||
|
||||
### 权衡
|
||||
|
||||
与对象配置相比的优点:
|
||||
|
||||
- 命令简单易学,易于记忆。
|
||||
- 命令只需要一个步骤即可对群集进行更改。
|
||||
|
||||
与对象配置相比的缺点:
|
||||
|
||||
- 命令不与变更审核流程整合。
|
||||
- 命令不提供与更改相关联的审计跟踪。
|
||||
- 除了活动对象之外,命令不提供记录来源。
|
||||
- 命令不提供用于创建新对象的模板。
|
||||
|
||||
## 命令式对象配置
|
||||
|
||||
在命令式对象配置中,`kubectl` 命令指定操作(创建,替换等),可选标志和至少一个文件名称。指定的文件必须包含对象的完整定义以 YAML 或 JSON 格式。
|
||||
|
||||
请参阅[参考资源](https://kubernetes.io/docs/resources-reference/v1.6/)
|
||||
查看有关对象定义的更多细节。
|
||||
|
||||
**警告:** 命令式 `replace` 命令用新提供的命令替换现有资源规格,将对配置文件中缺少的对象的所有更改都丢弃。这种方法不应更新与配置文件无关的资源类型。例如,`LoadBalancer` 类型的服务使其 `externalIPs` 字段与集群的配置无关。
|
||||
|
||||
### 例子
|
||||
|
||||
创建对象定义配置文件:
|
||||
|
||||
```sh
|
||||
kubectl create -f nginx.yaml
|
||||
```
|
||||
|
||||
删除两个配置文件中定义的对象:
|
||||
|
||||
```sh
|
||||
kubectl delete -f nginx.yaml -f redis.yaml
|
||||
```
|
||||
|
||||
通过覆写实时配置更新配置文件中定义的对象:
|
||||
|
||||
```sh
|
||||
kubectl replace -f nginx.yaml
|
||||
```
|
||||
|
||||
### 权衡
|
||||
|
||||
与命令式的命令相比的优点:
|
||||
|
||||
- 对象配置可以存储在源码控制系统中,如Git。
|
||||
- 对象配置可以与进程集成,例如在推送和审计跟踪之前查看更改。
|
||||
- 对象配置提供了一个用于创建新对象的模板。
|
||||
|
||||
与命令式的命令相比的缺点:
|
||||
|
||||
- 对象配置需要对对象模式有基本的了解。
|
||||
- 对象配置需要编写 YAML 文件的附加步骤。
|
||||
|
||||
与声明式对象配置相比的优势:
|
||||
|
||||
- 命令对象配置行为更简单易懂。
|
||||
- 至于 Kubernetes 1.5 版本,命令式对象配置更为成熟。
|
||||
|
||||
与声明式对象配置相比的缺点:
|
||||
|
||||
- 命令对象配置最适合于文件,而不是目录。
|
||||
- 活动对象的更新必须反映在配置文件中,否则在下次更替时将丢失。
|
||||
|
||||
## 声明式对象配置
|
||||
|
||||
当使用声明式对象配置时,用户对本地存储的对象配置文件进行操作,但是用户没有定义要对文件执行的操作。通过 `kubectl` 自动检测每个对象进行创建、更新和删除操作。这样可以在目录层级上工作,因为不同的对象可能需要不同的操作。
|
||||
|
||||
**注意:** 声明式对象配置保留由其他对象进行的更改,即使更改未合并到对象配置文件中。这可以通过使用 `patch` API 操作来写入观察到的差异,而不是使用`replace` API 操作来替换整个对象的配置。
|
||||
|
||||
### 例子
|
||||
|
||||
处理`configs` 目录中的所有对象配置文件,创建或修补(patch)活动对象:
|
||||
|
||||
```sh
|
||||
kubectl apply -f configs/
|
||||
```
|
||||
|
||||
递归处理目录:
|
||||
|
||||
```sh
|
||||
kubectl apply -R -f configs/
|
||||
```
|
||||
|
||||
### 权衡
|
||||
|
||||
与命令式对象配置相比的优点:
|
||||
|
||||
- 直接对活动对象进行的更改将被保留,即使它们未被并入到配置文件中。
|
||||
- 声明式对象配置更好地支持目录操作,并自动检测每个对象的操作类型 (创建、修补,删除)。
|
||||
|
||||
与命令式对象配置相比的缺点:
|
||||
|
||||
- 声明式对象配置在意外情况下难以调试和了解结果。
|
||||
- 使用差异的部分更新会创建复杂的合并和补丁操作。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
- [使用命令式的命令管理 Kubernetes 对象](/docs/tutorials/object-management-kubectl/imperative-object-management-command/)
|
||||
- [使用对象配置管理 Kubernetes 对象(必要)](/docs/tutorials/object-management-kubectl/imperative-object-management-configuration/)
|
||||
- [使用对象配置(声明式)管理 Kubernetes 对象](/docs/tutorials/object-management-kubectl/declarative-object-management-configuration/)
|
||||
- [Kubectl 命令参考](/docs/user-guide/kubectl/v1.6/)
|
||||
- [Kubernetes 对象模式参考](/docs/resources-reference/v1.6/)
|
||||
|
||||
{{< comment >}}
|
||||
{{< /comment >}}
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
---
|
||||
|
||||
title: 使用 Source IP
|
||||
content_template: templates/tutorial
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
Kubernetes 集群中运行的应用通过抽象的 Service 查找彼此,相互通信和连接外部世界。本文揭示了发送到不同类型 Services 的数据包源 IP 的内幕,你可以根据需求改变这个行为。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture 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](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 一个虚拟 IP, 例如分配给每个 Kubernetes Service 的 IP
|
||||
* [Kube-proxy](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 一个网络守护程序,在每个节点上协调 Service VIP 管理
|
||||
|
||||
|
||||
## 准备工作
|
||||
|
||||
|
||||
你必须拥有一个正常工作的 Kubernetes 1.5 集群,用来运行本文中的示例。该示例使用一个简单的 nginx webserver 回送它接收到的请求的 HTTP 头中的源 IP 地址。你可以像下面这样创建它:
|
||||
|
||||
```console
|
||||
$ kubectl run source-ip-app --image=k8s.gcr.io/echoserver:1.4
|
||||
deployment "source-ip-app" created
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture objectives %}}
|
||||
|
||||
|
||||
* 通过多种类型的 Services 暴露一个简单应用
|
||||
* 理解每种 Service 类型如何处理源 IP NAT
|
||||
* 理解保留源 IP 的折中
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture lessoncontent %}}
|
||||
|
||||
|
||||
## Type=ClusterIP 类型 Services 的 Source IP
|
||||
|
||||
|
||||
如果你的 kube-proxy 运行在 [iptables 模式](/docs/user-guide/services/#proxy-mode-iptables)下,从集群内部发送到 ClusterIP 的包永远不会进行源地址 NAT,这从 Kubernetes 1.2 开始是默认选项。Kube-proxy 通过一个 `proxyMode` endpoint 暴露它的模式。
|
||||
|
||||
```console
|
||||
$ kubectl get nodes
|
||||
NAME STATUS AGE VERSION
|
||||
kubernetes-minion-group-6jst Ready 2h v1.6.0+fff5156
|
||||
kubernetes-minion-group-cx31 Ready 2h v1.6.0+fff5156
|
||||
kubernetes-minion-group-jj1t Ready 2h v1.6.0+fff5156
|
||||
|
||||
kubernetes-minion-group-6jst $ curl localhost:10249/proxyMode
|
||||
iptables
|
||||
```
|
||||
|
||||
|
||||
你可以通过在 source IP 应用上创建一个服务来测试源 IP 保留。
|
||||
|
||||
```console
|
||||
$ kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
|
||||
service "clusterip" exposed
|
||||
|
||||
$ kubectl get svc clusterip
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
clusterip 10.0.170.92 <none> 80/TCP 51s
|
||||
```
|
||||
|
||||
|
||||
从相同集群中的一个 pod 访问这个 `ClusterIP`:
|
||||
|
||||
```console
|
||||
$ kubectl run busybox -it --image=busybox --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.
|
||||
|
||||
# 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 -qO - 10.0.170.92
|
||||
CLIENT VALUES:
|
||||
client_address=10.244.3.8
|
||||
command=GET
|
||||
...
|
||||
```
|
||||
|
||||
如果客户端 pod 和 服务端 pod 在相同的节点上,client_address 就是客户端 pod 的 IP 地址。但是,如果它们在不同的节点上, client_address 将会是客户端 pod 所在节点的 flannel IP 地址。
|
||||
|
||||
|
||||
## Type=NodePort 类型 Services 的 Source IP
|
||||
|
||||
|
||||
对于 Kubernetes 1.5,发送给类型为 [Type=NodePort](/docs/user-guide/services/#type-nodeport) Services 的数据包默认进行源地址 NAT。你可以创建一个 `NodePort` Service 来进行测试:
|
||||
|
||||
```console
|
||||
$ kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
|
||||
service "nodeport" exposed
|
||||
|
||||
$ NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
|
||||
$ NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="ExternalIP")].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 的回复被发送回给客户端
|
||||
|
||||
|
||||
形象的:
|
||||
|
||||
```
|
||||
client
|
||||
\ ^
|
||||
\ \
|
||||
v \
|
||||
node 1 <--- node 2
|
||||
| ^ SNAT
|
||||
| | --->
|
||||
v |
|
||||
endpoint
|
||||
```
|
||||
|
||||
|
||||
为了防止这种情况发生,Kubernetes 提供了一个特性来保留客户端的源 IP 地址[(点击此处查看可用特性)](/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
|
||||
|
||||
|
||||
形象的:
|
||||
|
||||
```
|
||||
client
|
||||
^ / \
|
||||
/ / \
|
||||
/ v X
|
||||
node 1 node 2
|
||||
^ |
|
||||
| |
|
||||
| v
|
||||
endpoint
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Type=LoadBalancer 类型 Services 的 Source IP
|
||||
|
||||
|
||||
对于 Kubernetes 1.5,发送给类型为 [Type=LoadBalancer](/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
|
||||
|
||||
$ kubectl get svc loadbalancer
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
loadbalancer 10.0.65.118 104.198.149.140 80/TCP 5m
|
||||
|
||||
$ curl 104.198.149.140
|
||||
CLIENT VALUES:
|
||||
client_address=10.240.0.5
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
然而,如果你的集群运行在 Google Kubernetes Engine/GCE 上,设置 `service.spec.externalTrafficPolicy` 字段值为 `Local` 可以强制使*没有* endpoints 的节点把他们自己从负载均衡流量的可选节点名单中删除。这是通过故意使它们健康检查失败达到的。
|
||||
|
||||
|
||||
形象的:
|
||||
|
||||
```
|
||||
client
|
||||
|
|
||||
lb VIP
|
||||
/ ^
|
||||
v /
|
||||
health check ---> node 1 node 2 <--- health check
|
||||
200 <--- ^ | ---> 500
|
||||
| V
|
||||
endpoint
|
||||
```
|
||||
|
||||
|
||||
你可以设置 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` 路径上提供的用于健康检查的端口。你可以这样测试:
|
||||
|
||||
```
|
||||
$ 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-minion-group-6jst
|
||||
|
||||
kubernetes-minion-group-6jst $ curl localhost:32122/healthz
|
||||
1 Service Endpoints found
|
||||
|
||||
kubernetes-minion-group-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 协议](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt)。
|
||||
第二类负载均衡器可以通过简单的在保存于 Service 的 `service.spec.healthCheckNodePort` 字段上创建一个 HTTP 健康检查点来使用上面描述的特性。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture cleanup %}}
|
||||
|
||||
|
||||
删除服务:
|
||||
|
||||
```console
|
||||
$ kubectl delete svc -l run=source-ip-app
|
||||
```
|
||||
|
||||
|
||||
删除 Deployment、ReplicaSet 和 Pod:
|
||||
|
||||
```console
|
||||
$ kubectl delete deployment source-ip-app
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 学习更多关于 [通过 services 连接应用](/docs/concepts/services-networking/connect-applications-service/)
|
||||
* 学习更多关于 [负载均衡](/docs/user-guide/load-balancer)
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# This is an image with Percona XtraBackup, mysql-client and ncat installed.
|
||||
FROM debian:jessie
|
||||
|
||||
RUN \
|
||||
echo "deb http://repo.percona.com/apt jessie main" > /etc/apt/sources.list.d/percona.list \
|
||||
&& echo "deb-src http://repo.percona.com/apt jessie main" >> /etc/apt/sources.list.d/percona.list \
|
||||
&& apt-key adv --keyserver keys.gnupg.net --recv-keys 8507EFA5
|
||||
|
||||
RUN \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
percona-xtrabackup-24 \
|
||||
mysql-client \
|
||||
nmap \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
CMD ["bash"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
name: cassandra
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: 9042
|
||||
selector:
|
||||
app: cassandra
|
||||
@@ -0,0 +1,94 @@
|
||||
apiVersion: "apps/v1beta1"
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: cassandra
|
||||
spec:
|
||||
serviceName: cassandra
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
spec:
|
||||
containers:
|
||||
- name: cassandra
|
||||
image: gcr.io/google-samples/cassandra:v12
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 7000
|
||||
name: intra-node
|
||||
- containerPort: 7001
|
||||
name: tls-intra-node
|
||||
- containerPort: 7199
|
||||
name: jmx
|
||||
- containerPort: 9042
|
||||
name: cql
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 1Gi
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"]
|
||||
env:
|
||||
- name: MAX_HEAP_SIZE
|
||||
value: 512M
|
||||
- name: HEAP_NEWSIZE
|
||||
value: 100M
|
||||
- name: CASSANDRA_SEEDS
|
||||
value: "cassandra-0.cassandra.default.svc.cluster.local"
|
||||
- name: CASSANDRA_CLUSTER_NAME
|
||||
value: "K8Demo"
|
||||
- name: CASSANDRA_DC
|
||||
value: "DC1-K8Demo"
|
||||
- name: CASSANDRA_RACK
|
||||
value: "Rack1-K8Demo"
|
||||
- name: CASSANDRA_AUTO_BOOTSTRAP
|
||||
value: "false"
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- /ready-probe.sh
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 5
|
||||
# These volume mounts are persistent. They are like inline claims,
|
||||
# but not exactly because the names need to match exactly one of
|
||||
# the stateful pod volumes.
|
||||
volumeMounts:
|
||||
- name: cassandra-data
|
||||
mountPath: /cassandra_data
|
||||
# These are converted to volume claims by the controller
|
||||
# and mounted at the paths mentioned above.
|
||||
# do not use these in production until ssd GCEPersistentDisk or other ssd pd
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: cassandra-data
|
||||
annotations:
|
||||
volume.beta.kubernetes.io/storage-class: fast
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
kind: StorageClass
|
||||
apiVersion: storage.k8s.io/v1
|
||||
metadata:
|
||||
name: fast
|
||||
provisioner: k8s.io/minikube-hostpath
|
||||
parameters:
|
||||
type: pd-ssd
|
||||
@@ -0,0 +1,851 @@
|
||||
---
|
||||
title: "Example: Deploying Cassandra with Stateful Sets"
|
||||
title: “示例:使用 Stateful Sets 部署 Cassandra”
|
||||
---
|
||||
|
||||
|
||||
## 目录
|
||||
|
||||
- [准备工作](#prerequisites)
|
||||
- [Cassandra docker 镜像](#cassandra-docker)
|
||||
- [快速入门](#quickstart)
|
||||
- [步骤1:创建 Cassandra Headless Service](#step-1-create-a-cassandra-headless-service)
|
||||
- [步骤2:使用 StatefulSet 创建 Cassandra Ring环](#step-2-use-a-statefulset-to-create-cassandra-ring)
|
||||
- [步骤3:验证并修改 Cassandra StatefulSet](#step-3-validate-and-modify-the-cassandra-statefulset)
|
||||
- [步骤4:删除 Cassandra StatefulSet](#step-4-delete-cassandra-statefulset)
|
||||
- [步骤5:使用 Replication Controller 创建 Cassandra 节点 pods](#step-5-use-a-replication-controller-to-create-cassandra-node-pods)
|
||||
- [步骤6:Cassandra 集群扩容](#step-6-scale-up-the-cassandra-cluster)
|
||||
- [步骤7:删除 Replication Controller](#step-7-delete-the-replication-controller)
|
||||
- [步骤8:使用 DaemonSet 替换 Replication Controller](#step-8-use-a-daemonset-instead-of-a-replication-controller)
|
||||
- [步骤9:资源清理](#step-9-resource-cleanup)
|
||||
- [Seed Provider Source](#seed-provider-source)
|
||||
|
||||
|
||||
|
||||
下文描述了在 Kubernetes 上部署一个_云原生_ [Cassandra](http://cassandra.apache.org/) 的过程。当我们说_云原生_时,指的是一个应用能够理解它运行在一个集群管理器内部,并且使用这个集群的管理基础设施来帮助实现这个应用。特别的,本例使用了一个自定义的 Cassandra `SeedProvider` 帮助 Cassandra 发现新加入集群 Cassandra 节点。
|
||||
|
||||
|
||||
本示例也使用了Kubernetes的一些核心组件:
|
||||
|
||||
- [_Pods_](/docs/user-guide/pods)
|
||||
- [ _Services_](/docs/user-guide/services)
|
||||
- [_Replication Controllers_](/docs/user-guide/replication-controller)
|
||||
- [_Stateful Sets_](/docs/concepts/workloads/controllers/statefulset/)
|
||||
- [_Daemon Sets_](/docs/admin/daemons)
|
||||
|
||||
|
||||
|
||||
## 准备工作
|
||||
|
||||
|
||||
本示例假设你已经安装运行了一个 Kubernetes集群(版本 >=1.2),并且还在某个路径下安装了 [`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/) 命令行工具。请查看 [getting started guides](https://kubernetes.io/docs/getting-started-guides/) 获取关于你的平台的安装说明。
|
||||
|
||||
|
||||
本示例还需要一些代码和配置文件。为了避免手动输入,你可以 `git clone` Kubernetes 源到你本地。
|
||||
|
||||
|
||||
## Cassandra Docker镜像
|
||||
|
||||
|
||||
Pods 使用来自 Google 的 [container registry](https://cloud.google.com/container-registry/docs/) 的 [```gcr.io/google-samples/cassandra:v12```](https://github.com/kubernetes/examples/blob/master/cassandra/image/Dockerfile) 镜像。这个 docker 镜像基于 `debian:jessie` 并包含 OpenJDK 8。该镜像包含一个从 Apache Debian 源中安装的标准 Cassandra。你可以通过使用环境变量改变插入到 `cassandra.yaml` 文件中的参数值。
|
||||
|
||||
| ENV VAR | DEFAULT VALUE |
|
||||
| ---------------------- | :------------: |
|
||||
| CASSANDRA_CLUSTER_NAME | 'Test Cluster' |
|
||||
| CASSANDRA_NUM_TOKENS | 32 |
|
||||
| CASSANDRA_RPC_ADDRESS | 0.0.0.0 |
|
||||
|
||||
|
||||
## 快速入门
|
||||
|
||||
|
||||
如果你希望直接跳到我们使用的命令,以下是全部步骤:
|
||||
|
||||
```sh
|
||||
#
|
||||
# StatefulSet
|
||||
#
|
||||
|
||||
# clone the example repository
|
||||
git clone https://github.com/kubernetes/examples
|
||||
cd examples
|
||||
|
||||
# create a service to track all cassandra statefulset nodes
|
||||
kubectl create -f cassandra/cassandra-service.yaml
|
||||
|
||||
# create a statefulset
|
||||
kubectl create -f cassandra/cassandra-statefulset.yaml
|
||||
|
||||
# validate the Cassandra cluster. Substitute the name of one of your pods.
|
||||
kubectl exec -ti cassandra-0 -- nodetool status
|
||||
|
||||
# cleanup
|
||||
grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
|
||||
&& kubectl delete statefulset,po -l app=cassandra \
|
||||
&& echo "Sleeping $grace" \
|
||||
&& sleep $grace \
|
||||
&& kubectl delete pvc -l app=cassandra
|
||||
|
||||
#
|
||||
# Resource Controller Example
|
||||
#
|
||||
|
||||
# create a replication controller to replicate cassandra nodes
|
||||
kubectl create -f cassandra/cassandra-controller.yaml
|
||||
|
||||
# validate the Cassandra cluster. Substitute the name of one of your pods.
|
||||
kubectl exec -ti cassandra-xxxxx -- nodetool status
|
||||
|
||||
# scale up the Cassandra cluster
|
||||
kubectl scale rc cassandra --replicas=4
|
||||
|
||||
# delete the replication controller
|
||||
kubectl delete rc cassandra
|
||||
|
||||
#
|
||||
# Create a DaemonSet to place a cassandra node on each kubernetes node
|
||||
#
|
||||
|
||||
kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false
|
||||
|
||||
# resource cleanup
|
||||
kubectl delete service -l app=cassandra
|
||||
kubectl delete daemonset cassandra
|
||||
```
|
||||
|
||||
|
||||
## 步骤1:创建 Cassandra Headless Service
|
||||
|
||||
|
||||
Kubernetes _[Service](/docs/user-guide/services)_ 描述一组执行同样任务的 [_Pods_](/docs/user-guide/pods)。在Kubernetes中,一个应用的原子调度单位是一个 Pod:一个或多个_必须_调度到相同主机上的容器。
|
||||
|
||||
|
||||
这个 Service 用于在Kubernetes 集群内部进行 Cassandra 客户端和 Cassandra Pods之间的 DNS 查找。
|
||||
|
||||
|
||||
以下为这个 service 的描述:
|
||||
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
name: cassandra
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: 9042
|
||||
selector:
|
||||
app: cassandra
|
||||
```
|
||||
|
||||
|
||||
[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-service.yaml)
|
||||
|
||||
|
||||
|
||||
为 StatefulSet 创建 service
|
||||
|
||||
|
||||
```console
|
||||
$ kubectl create -f cassandra/cassandra-service.yaml
|
||||
```
|
||||
|
||||
|
||||
以下命令显示了 service 是否被成功创建。
|
||||
|
||||
```console
|
||||
$ kubectl get svc cassandra
|
||||
```
|
||||
|
||||
|
||||
命令的响应应该像这样:
|
||||
|
||||
```console
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
cassandra None <none> 9042/TCP 45s
|
||||
```
|
||||
|
||||
|
||||
如果返回错误则表示 service 创建失败。
|
||||
|
||||
|
||||
## 步骤2:使用 StatefulSet 创建 Cassandra Ring环
|
||||
|
||||
|
||||
StatefulSets(以前叫做 PetSets)特性在 Kubernetes 1.5 中升级为一个 <i>Beta</i> 组件。在集群环境中部署类似于 Cassandra 的有状态分布式应用是一项具有挑战性的工作。我们实现了StatefulSet,极大的简化了这个过程。本示例使用了 StatefulSet 的多个特性,但其本身超出了本文的范围。[请参考 Stateful Set 文档。](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
|
||||
|
||||
|
||||
以下是StatefulSet 的清单文件,用于创建一个由三个 pods 组成的 Cassandra ring环。
|
||||
|
||||
|
||||
本示例使用了 GCE Storage Class,请根据你运行的云平台做适当的修改。
|
||||
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: "apps/v1beta1"
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: cassandra
|
||||
spec:
|
||||
serviceName: cassandra
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
spec:
|
||||
containers:
|
||||
- name: cassandra
|
||||
image: gcr.io/google-samples/cassandra:v12
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 7000
|
||||
name: intra-node
|
||||
- containerPort: 7001
|
||||
name: tls-intra-node
|
||||
- containerPort: 7199
|
||||
name: jmx
|
||||
- containerPort: 9042
|
||||
name: cql
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: "500m"
|
||||
memory: 1Gi
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"]
|
||||
env:
|
||||
- name: MAX_HEAP_SIZE
|
||||
value: 512M
|
||||
- name: HEAP_NEWSIZE
|
||||
value: 100M
|
||||
- name: CASSANDRA_SEEDS
|
||||
value: "cassandra-0.cassandra.default.svc.cluster.local"
|
||||
- name: CASSANDRA_CLUSTER_NAME
|
||||
value: "K8Demo"
|
||||
- name: CASSANDRA_DC
|
||||
value: "DC1-K8Demo"
|
||||
- name: CASSANDRA_RACK
|
||||
value: "Rack1-K8Demo"
|
||||
- name: CASSANDRA_AUTO_BOOTSTRAP
|
||||
value: "false"
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- /ready-probe.sh
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 5
|
||||
# These volume mounts are persistent. They are like inline claims,
|
||||
# but not exactly because the names need to match exactly one of
|
||||
# the stateful pod volumes.
|
||||
volumeMounts:
|
||||
- name: cassandra-data
|
||||
mountPath: /cassandra_data
|
||||
# These are converted to volume claims by the controller
|
||||
# and mounted at the paths mentioned above.
|
||||
# do not use these in production until ssd GCEPersistentDisk or other ssd pd
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: cassandra-data
|
||||
annotations:
|
||||
volume.beta.kubernetes.io/storage-class: fast
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
kind: StorageClass
|
||||
apiVersion: storage.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: fast
|
||||
provisioner: kubernetes.io/gce-pd
|
||||
parameters:
|
||||
type: pd-ssd
|
||||
```
|
||||
|
||||
|
||||
[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-statefulset.yaml)
|
||||
|
||||
|
||||
|
||||
创建 Cassandra StatefulSet 如下:
|
||||
|
||||
```console
|
||||
$ kubectl create -f cassandra/cassandra-statefulset.yaml
|
||||
```
|
||||
|
||||
|
||||
## 步骤3:验证和修改 Cassandra StatefulSet
|
||||
|
||||
|
||||
这个 StatefulSet 的部署展示了 StatefulSets 提供的两个新特性:
|
||||
|
||||
1. Pod 的名称已知
|
||||
2. Pod 以递增顺序部署
|
||||
|
||||
|
||||
首先,运行下面的 `kubectl` 命令,验证 StatefulSet 已经被成功部署。
|
||||
|
||||
```console
|
||||
$ kubectl get statefulset cassandra
|
||||
```
|
||||
|
||||
|
||||
这个命令的响应应该像这样:
|
||||
|
||||
```console
|
||||
NAME DESIRED CURRENT AGE
|
||||
cassandra 3 3 13s
|
||||
```
|
||||
|
||||
|
||||
接下来观察 Cassandra pods 以一个接一个的形式部署。StatefulSet 资源按照数字序号的模式部署 pods:1, 2, 3 等。如果在 pods 部署前执行下面的命令,你就能够看到这种顺序的创建过程。
|
||||
|
||||
```console
|
||||
$ kubectl get pods -l="app=cassandra"
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
cassandra-0 1/1 Running 0 1m
|
||||
cassandra-1 0/1 ContainerCreating 0 8s
|
||||
```
|
||||
|
||||
|
||||
上面的示例显示了三个 Cassandra StatefulSet pods 中的两个已经部署。一旦所有的 pods 都部署成功,相同的命令会显示一个完整的StatefulSet。
|
||||
|
||||
```console
|
||||
$ kubectl get pods -l="app=cassandra"
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
运行 Cassandra 工具 `nodetool` 将显示 ring环的状态。
|
||||
|
||||
```console
|
||||
$ kubectl exec cassandra-0 -- nodetool status
|
||||
Datacenter: DC1-K8Demo
|
||||
======================
|
||||
Status=Up/Down
|
||||
|/ State=Normal/Leaving/Joining/Moving
|
||||
-- Address Load Tokens Owns (effective) Host ID Rack
|
||||
UN 10.4.2.4 65.26 KiB 32 63.7% a9d27f81-6783-461d-8583-87de2589133e Rack1-K8Demo
|
||||
UN 10.4.0.4 102.04 KiB 32 66.7% 5559a58c-8b03-47ad-bc32-c621708dc2e4 Rack1-K8Demo
|
||||
UN 10.4.1.4 83.06 KiB 32 69.6% 9dce943c-581d-4c0e-9543-f519969cc805 Rack1-K8Demo
|
||||
```
|
||||
|
||||
|
||||
你也可以运行 `cqlsh` 来显示集群的 keyspaces。
|
||||
|
||||
```console
|
||||
$ kubectl exec cassandra-0 -- cqlsh -e 'desc keyspaces'
|
||||
|
||||
system_traces system_schema system_auth system system_distributed
|
||||
```
|
||||
|
||||
|
||||
你需要使用 `kubectl edit` 来增加或减小 Cassandra StatefulSet 的大小。你可以在 [文档](/docs/user-guide/kubectl/kubectl_edit) 中找到更多关于 edit 命令的信息。
|
||||
|
||||
|
||||
使用以下命令编辑 StatefulSet。
|
||||
|
||||
```console
|
||||
$ kubectl edit statefulset cassandra
|
||||
```
|
||||
|
||||
|
||||
这会在你的命令行中创建一个编辑器。你需要修改的行是 `replicas`。这个例子没有包含终端窗口的所有内容,下面示例中的最后一行就是你希望改变的 replicas 行。
|
||||
|
||||
```console
|
||||
# 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/v1beta1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
creationTimestamp: 2016-08-13T18:40:58Z
|
||||
generation: 1
|
||||
labels:
|
||||
app: cassandra
|
||||
name: cassandra
|
||||
namespace: default
|
||||
resourceVersion: "323"
|
||||
selfLink: /apis/apps/v1beta1/namespaces/default/statefulsets/cassandra
|
||||
uid: 7a219483-6185-11e6-a910-42010a8a0fc0
|
||||
spec:
|
||||
replicas: 3
|
||||
```
|
||||
|
||||
|
||||
按下面的示例修改清单文件并保存。
|
||||
|
||||
```console
|
||||
spec:
|
||||
replicas: 4
|
||||
```
|
||||
|
||||
|
||||
这个 StatefulSet 现在将包含四个 pods。
|
||||
|
||||
```console
|
||||
$ kubectl get statefulset cassandra
|
||||
```
|
||||
|
||||
|
||||
这个command的响应应该像这样:
|
||||
|
||||
```console
|
||||
NAME DESIRED CURRENT AGE
|
||||
cassandra 4 4 36m
|
||||
```
|
||||
|
||||
|
||||
对于 Kubernetes 1.5 发布版,beta StatefulSet 资源没有像 Deployment, ReplicaSet, Replication Controller或者 Job一样,包含 `kubectl scale` 功能,
|
||||
|
||||
|
||||
## 步骤4:删除 Cassandra StatefulSet
|
||||
|
||||
|
||||
删除或者缩容 StatefulSet 时不会删除与之关联的 volumes。这样做是为了优先保证安全。你的数据比其它会被自动清除的 StatefulSet 关联资源更宝贵。删除 Persistent Volume Claims 可能会导致关联的 volumes 被删除,这种行为依赖 storage class 和 reclaim policy。永远不要期望能在 claim 删除后访问一个 volume。
|
||||
|
||||
|
||||
使用如下命令删除 StatefulSet。
|
||||
|
||||
```console
|
||||
$ grace=$(kubectl get po cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
|
||||
&& kubectl delete statefulset -l app=cassandra \
|
||||
&& echo "Sleeping $grace" \
|
||||
&& sleep $grace \
|
||||
&& kubectl delete pvc -l app=cassandra
|
||||
```
|
||||
|
||||
|
||||
## 步骤5:使用 Replication Controller 创建 Cassandra 节点 pods
|
||||
|
||||
|
||||
Kubernetes _[Replication Controller](/docs/user-guide/replication-controller)_ 负责复制一个完全相同的 pods 集合。像 Service 一样,它具有一个 selector query,用来识别它的集合成员。和 Service 不一样的是,它还具有一个期望的副本数,并且会通过创建或删除 Pods来保证 Pods 的数量满足它期望的状态。
|
||||
|
||||
|
||||
和我们刚才定义的 Service 一起,Replication Controller 能够让我们轻松的构建一个复制的、可扩展的 Cassandra 集群。
|
||||
|
||||
|
||||
让我们创建一个具有两个初始副本的 replication controller。
|
||||
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: cassandra
|
||||
# The labels will be applied automatically
|
||||
# from the labels in the pod template, if not set
|
||||
# labels:
|
||||
# app: cassandra
|
||||
spec:
|
||||
replicas: 2
|
||||
# The selector will be applied automatically
|
||||
# from the labels in the pod template, if not set.
|
||||
# selector:
|
||||
# app: cassandra
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /run.sh
|
||||
resources:
|
||||
limits:
|
||||
cpu: 0.5
|
||||
env:
|
||||
- name: MAX_HEAP_SIZE
|
||||
value: 512M
|
||||
- name: HEAP_NEWSIZE
|
||||
value: 100M
|
||||
- name: CASSANDRA_SEED_PROVIDER
|
||||
value: "io.k8s.cassandra.KubernetesSeedProvider"
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
image: gcr.io/google-samples/cassandra:v12
|
||||
name: cassandra
|
||||
ports:
|
||||
- containerPort: 7000
|
||||
name: intra-node
|
||||
- containerPort: 7001
|
||||
name: tls-intra-node
|
||||
- containerPort: 7199
|
||||
name: jmx
|
||||
- containerPort: 9042
|
||||
name: cql
|
||||
volumeMounts:
|
||||
- mountPath: /cassandra_data
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
|
||||
[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-controller.yaml)
|
||||
|
||||
|
||||
|
||||
在这个描述中需要注意几件事情。
|
||||
|
||||
|
||||
`selector` 属性包含了控制器的 selector query。它能够被显式指定,或者在没有设置时,像此处一样从 pod 模板中的 labels 中自动应用。
|
||||
|
||||
|
||||
Pod 模板的标签 `app:cassandra` 匹配步骤1中的 Service selector。这就是 Service 如何选择 replication controller 创建的 pods 的原理。
|
||||
|
||||
|
||||
`replicas` 属性指明了期望的副本数量,在本例中最开始为 2。我们很快将要扩容更多数量。
|
||||
|
||||
|
||||
创建 Replication Controller:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl create -f cassandra/cassandra-controller.yaml
|
||||
|
||||
```
|
||||
|
||||
|
||||
你可以列出新建的 controller:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get rc -o wide
|
||||
NAME DESIRED CURRENT AGE CONTAINER(S) IMAGE(S) SELECTOR
|
||||
cassandra 2 2 11s cassandra gcr.io/google-samples/cassandra:v12 app=cassandra
|
||||
|
||||
```
|
||||
|
||||
|
||||
现在,如果你列出集群中的 pods,并且使用 `app=cassandra` 标签过滤,你应该能够看到两个 Cassandra pods。(`wide` 参数使你能够看到 pods 被调度到了哪个 Kubernetes 节点上)
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get pods -l="app=cassandra" -o wide
|
||||
NAME READY STATUS RESTARTS AGE NODE
|
||||
cassandra-21qyy 1/1 Running 0 1m kubernetes-minion-b286
|
||||
cassandra-q6sz7 1/1 Running 0 1m kubernetes-minion-9ye5
|
||||
|
||||
```
|
||||
|
||||
|
||||
因为这些 pods 拥有 `app=cassandra` 标签,它们被映射给了我们在步骤1中创建的 service。
|
||||
|
||||
|
||||
你可以使用下面的 service endpoint 查询命令来检查 Pods 是否对 Service 可用。
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get endpoints cassandra -o yaml
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
creationTimestamp: 2015-06-21T22:34:12Z
|
||||
labels:
|
||||
app: cassandra
|
||||
name: cassandra
|
||||
namespace: default
|
||||
resourceVersion: "944373"
|
||||
selfLink: /api/v1/namespaces/default/endpoints/cassandra
|
||||
uid: a3d6c25f-1865-11e5-a34e-42010af01bcc
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.244.3.15
|
||||
targetRef:
|
||||
kind: Pod
|
||||
name: cassandra
|
||||
namespace: default
|
||||
resourceVersion: "944372"
|
||||
uid: 9ef9895d-1865-11e5-a34e-42010af01bcc
|
||||
ports:
|
||||
- port: 9042
|
||||
protocol: TCP
|
||||
|
||||
```
|
||||
|
||||
|
||||
为了显示 `SeedProvider` 逻辑是按设想在运行,你可以使用 `nodetool` 命令来检查 Cassandra 集群的状态。为此,请使用 `kubectl exec` 命令,这样你就能在一个 Cassandra pod 上运行 `nodetool`。同样的,请替换 `cassandra-xxxxx` 为任意一个 pods的真实名字。
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
|
||||
Datacenter: datacenter1
|
||||
=======================
|
||||
Status=Up/Down
|
||||
|/ State=Normal/Leaving/Joining/Moving
|
||||
-- Address Load Tokens Owns (effective) Host ID Rack
|
||||
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
|
||||
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 步骤6:Cassandra集群扩容
|
||||
|
||||
|
||||
现在,让我们把 Cassandra 集群扩展到4个 pods。我们通过告诉 Replication Controller 现在我们需要4个副本来完成。
|
||||
|
||||
```sh
|
||||
|
||||
$ kubectl scale rc cassandra --replicas=4
|
||||
|
||||
```
|
||||
|
||||
|
||||
你可以看到列出了新的 pods:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get pods -l="app=cassandra" -o wide
|
||||
NAME READY STATUS RESTARTS AGE NODE
|
||||
cassandra-21qyy 1/1 Running 0 6m kubernetes-minion-b286
|
||||
cassandra-81m2l 1/1 Running 0 47s kubernetes-minion-b286
|
||||
cassandra-8qoyp 1/1 Running 0 47s kubernetes-minion-9ye5
|
||||
cassandra-q6sz7 1/1 Running 0 6m kubernetes-minion-9ye5
|
||||
|
||||
```
|
||||
|
||||
|
||||
一会儿你就能再次检查 Cassandra 集群的状态,你可以看到新的 pods 已经被自定义的 `SeedProvider` 检测到:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
|
||||
Datacenter: datacenter1
|
||||
=======================
|
||||
Status=Up/Down
|
||||
|/ State=Normal/Leaving/Joining/Moving
|
||||
-- Address Load Tokens Owns (effective) Host ID Rack
|
||||
UN 10.244.0.6 51.67 KB 256 48.9% d07b23a5-56a1-4b0b-952d-68ab95869163 rack1
|
||||
UN 10.244.1.5 84.71 KB 256 50.7% e060df1f-faa2-470c-923d-ca049b0f3f38 rack1
|
||||
UN 10.244.1.6 84.71 KB 256 47.0% 83ca1580-4f3c-4ec5-9b38-75036b7a297f rack1
|
||||
UN 10.244.0.5 68.2 KB 256 53.4% 72ca27e2-c72c-402a-9313-1e4b61c2f839 rack1
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 步骤7:删除 Replication Controller
|
||||
|
||||
|
||||
在你开始步骤5之前, __删除__你在上面创建的 __replication controller__。
|
||||
|
||||
```sh
|
||||
|
||||
$ kubectl delete rc cassandra
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 步骤8:使用 DaemonSet 替换 Replication Controller
|
||||
|
||||
|
||||
在 Kubernetes中,[_Daemon Set_](/docs/admin/daemons) 能够将 pods 一对一的分布到 Kubernetes 节点上。和 _ReplicationController_ 相同的是它也有一个用于识别它的集合成员的 selector query。但和 _ReplicationController_ 不同的是,它拥有一个节点 selector,用于限制基于模板的 pods 可以调度的节点。并且 pod 的复制不是基于一个设置的数量,而是为每一个节点分配一个 pod。
|
||||
|
||||
|
||||
示范用例:当部署到云平台时,预期情况是实例是短暂的并且随时可能终止。Cassandra 被搭建成为在各个节点间复制数据以便于实现数据冗余。这样的话,即使一个实例终止了,存储在它上面的数据却没有,并且集群会通过重新复制数据到其它运行节点来作为响应。
|
||||
|
||||
|
||||
`DaemonSet` 设计为在 Kubernetes 集群中的每个节点上放置一个 pod。那样就会给我们带来数据冗余度。让我们创建一个 DaemonSet 来启动我们的存储集群:
|
||||
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
labels:
|
||||
name: cassandra
|
||||
name: cassandra
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cassandra
|
||||
spec:
|
||||
# Filter to specific nodes:
|
||||
# nodeSelector:
|
||||
# app: cassandra
|
||||
containers:
|
||||
- command:
|
||||
- /run.sh
|
||||
env:
|
||||
- name: MAX_HEAP_SIZE
|
||||
value: 512M
|
||||
- name: HEAP_NEWSIZE
|
||||
value: 100M
|
||||
- name: CASSANDRA_SEED_PROVIDER
|
||||
value: "io.k8s.cassandra.KubernetesSeedProvider"
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
image: gcr.io/google-samples/cassandra:v12
|
||||
name: cassandra
|
||||
ports:
|
||||
- containerPort: 7000
|
||||
name: intra-node
|
||||
- containerPort: 7001
|
||||
name: tls-intra-node
|
||||
- containerPort: 7199
|
||||
name: jmx
|
||||
- containerPort: 9042
|
||||
name: cql
|
||||
# If you need it, it will go away in C* 4.0.
|
||||
#- containerPort: 9160
|
||||
# name: thrift
|
||||
resources:
|
||||
requests:
|
||||
cpu: 0.5
|
||||
volumeMounts:
|
||||
- mountPath: /cassandra_data
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
|
||||
[下载示例](https://raw.githubusercontent.com/kubernetes/examples/master/cassandra-daemonset.yaml)
|
||||
|
||||
|
||||
|
||||
这个 DaemonSet 绝大部分的定义和上面的 ReplicationController 完全相同;它只是简单的给 daemon set 一个创建新的 Cassandra pods 的方法,并且以集群中所有的 Cassandra 节点为目标。
|
||||
|
||||
|
||||
不同之处在于 `nodeSelector` 属性,它允许 DaemonSet 以全部节点的一个子集为目标(你可以向其他资源一样标记节点),并且没有 `replicas` 属性,因为它使用1对1的 node-pod 关系。
|
||||
|
||||
|
||||
创建这个 DaemonSet:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl create -f cassandra/cassandra-daemonset.yaml
|
||||
|
||||
```
|
||||
|
||||
|
||||
你可能需要禁用配置文件检查,像这样:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl create -f cassandra/cassandra-daemonset.yaml --validate=false
|
||||
|
||||
```
|
||||
|
||||
|
||||
你可以看到 DaemonSet 已经在运行:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get daemonset
|
||||
NAME DESIRED CURRENT NODE-SELECTOR
|
||||
cassandra 3 3 <none>
|
||||
|
||||
```
|
||||
|
||||
|
||||
现在,如果你列出集群中的 pods,并且使用 `app=cassandra` 标签过滤,你应该能够看到你的网络中的每一个节点上都有一个(且只有一个)新的 cassandra pod。
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl get pods -l="app=cassandra" -o wide
|
||||
NAME READY STATUS RESTARTS AGE NODE
|
||||
cassandra-ico4r 1/1 Running 0 4s kubernetes-minion-rpo1
|
||||
cassandra-kitfh 1/1 Running 0 1s kubernetes-minion-9ye5
|
||||
cassandra-tzw89 1/1 Running 0 2s kubernetes-minion-b286
|
||||
|
||||
```
|
||||
|
||||
|
||||
为了证明这是按设想的在工作,你可以再次使用 `nodetool` 命令来检查集群的状态。为此,请使用 `kubectl exec` 命令在任何一个新建的 cassandra pods 上运行 `nodetool`。
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl exec -ti cassandra-xxxxx -- nodetool status
|
||||
Datacenter: datacenter1
|
||||
=======================
|
||||
Status=Up/Down
|
||||
|/ State=Normal/Leaving/Joining/Moving
|
||||
-- Address Load Tokens Owns (effective) Host ID Rack
|
||||
UN 10.244.0.5 74.09 KB 256 100.0% 86feda0f-f070-4a5b-bda1-2eeb0ad08b77 rack1
|
||||
UN 10.244.4.2 32.45 KB 256 100.0% 0b1be71a-6ffb-4895-ac3e-b9791299c141 rack1
|
||||
UN 10.244.3.3 51.28 KB 256 100.0% dafe3154-1d67-42e1-ac1d-78e7e80dce2b rack1
|
||||
|
||||
```
|
||||
|
||||
|
||||
**注意**:这个示例让你在创建 DaemonSet 前删除了 cassandra的Replication Controller。这是因为为了保持示例的简单,RC 和 DaemonSet 使用了相同的 `app=cassandra` 标签(如此它们的 pods 映射到了我们创建的 service,这样 SeedProvider 就能识别它们)。
|
||||
|
||||
|
||||
如果我们没有预先删除 RC,这两个资源在需要运行多少 pods 上将会发生冲突。如果希望的话,我们可以使用额外的标签和 selectors 来支持同时运行它们。
|
||||
|
||||
|
||||
## 步骤9:资源清理
|
||||
|
||||
|
||||
当你准备删除你的资源时,按以下执行:
|
||||
|
||||
```console
|
||||
|
||||
$ kubectl delete service -l app=cassandra
|
||||
$ kubectl delete daemonset cassandra
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 自定义 Seed Provider
|
||||
|
||||
|
||||
我们使用了一个自定义的 [`SeedProvider`](https://svn.apache.org/repos/asf/cassandra/trunk/src/java/org/apache/cassandra/locator/SeedProvider.java) 来在 Kubernetes 之上运行 Cassandra。仅当你通过 replication control 或者 daemonset 部署 Cassandra 时才需要使用自定义的 seed provider。在 Cassandra 中,`SeedProvider` 引导 Cassandra 使用 gossip 协议来查找其它 Cassandra 节点。Seed 地址是被视为连接端点的主机。Cassandra 实例使用 seed 列表来查找彼此并学习 ring环拓扑。[`KubernetesSeedProvider`](https://github.com/kubernetes/kubernetes/blob/master/examples/storage/cassandra/java/src/main/java/io/k8s/cassandra/KubernetesSeedProvider.java) 通过 Kubernetes API 发现 Cassandra seeds IP 地址,那些 Cassandra 实例在 Cassandra Service 中定义。
|
||||
|
||||
|
||||
请查阅自定义 seed provider 的 [README](https://git.k8s.io/examples/cassandra/java/README.md) 文档,获取 `KubernetesSeedProvider` 进阶配置。对于本示例来说,你应该不需要自定义 Seed Provider 的配置。
|
||||
|
||||
|
||||
查看本示例的 [image](https://github.com/kubernetes/examples/tree/master/cassandra/image) 目录,了解如何构建容器的 docker 镜像及其内容。
|
||||
|
||||
|
||||
你可能还注意到我们设置了一些 Cassandra 参数(`MAX_HEAP_SIZE`和`HEAP_NEWSIZE`),并且增加了关于 [namespace](/docs/user-guide/namespaces) 的信息。我们还告诉 Kubernetes 容器暴露了 `CQL` 和 `Thrift` API 端口。最后,我们告诉集群管理器我们需要 0.1 cpu(0.1 核)。
|
||||
|
||||
|
||||
|
||||
[!Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/cassandra/README.md?pixel)]()
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
---
|
||||
title: "基于 Persistent Volumes 搭建 WordPress 和 MySQL 应用"
|
||||
approvers:
|
||||
- ahmetb
|
||||
- jeffmendoza
|
||||
---
|
||||
|
||||
|
||||
本示例描述了如何在 Kubeernetes 上持久化安装 [WordPress](https://wordpress.org/) 和
|
||||
[MySQL](https://www.mysql.com/) 。在这个安装里我们将使用官方的 [mysql](https://registry.hub.docker.com/_/mysql/) 和
|
||||
[wordpress](https://registry.hub.docker.com/_/wordpress/) 镜像(WordPress 镜像包含一个 Apache 服务)。
|
||||
|
||||
|
||||
展示的 Kubernetes 概念:
|
||||
|
||||
* [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) 定义持久化磁盘(磁盘生命周期不和 Pods 绑定)。
|
||||
* [Services](https://kubernetes.io/docs/concepts/services-networking/service/) 使得 Pods 能够找到其它 Pods。
|
||||
* [External Load Balancers](https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer) 对外暴露 Services。
|
||||
* [Deployments](http://kubernetes.io/docs/user-guide/deployments/) 确保 Pods 持续运行。
|
||||
* [Secrets](http://kubernetes.io/docs/user-guide/secrets/) 保存敏感密码信息。
|
||||
|
||||
|
||||
## 快速入门
|
||||
|
||||
|
||||
在一个名为 `password.txt` 的文件中放置你期望的 MySQL 密码,结尾不要有空行。如果你的编辑器添加了一个空行,开始的 `tr` 命令将会删除它。
|
||||
|
||||
|
||||
**请注意:**如果你的集群强制启用 **_selinux_** 特性并且你将使用 [Host Path](#host-path) 作为存储,请遵照这个[额外步骤](#selinux)。
|
||||
|
||||
```shell
|
||||
tr --delete '\n' <password.txt >.strippedpassword.txt && mv .strippedpassword.txt password.txt
|
||||
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/local-volumes.yaml
|
||||
kubectl create secret generic mysql-pass --from-file=password.txt
|
||||
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/mysql-deployment.yaml
|
||||
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/wordpress-deployment.yaml
|
||||
```
|
||||
|
||||
|
||||
## 目录
|
||||
|
||||
|
||||
|
||||
|
||||
[在 Kubernetes 上持久化安装 MySQL 和 WordPress](#persistent-installation-of-mysql-and-wordpress-on-kubernetes)
|
||||
- [快速入门](#quickstart)
|
||||
- [目录](#table-of-contents)
|
||||
- [集群要求](#cluster-requirements)
|
||||
- [决定在哪里存储你的数据](#decide-where-you-will-store-your-data)
|
||||
- [Host Path](#host-path)
|
||||
- [SELinux](#selinux)
|
||||
- [GCE Persistent Disk](#gce-persistent-disk)
|
||||
- [创建 MySQL 密码 secret](#create-the-mysql-password-secret)
|
||||
- [部署 MySQL](#deploy-mysql)
|
||||
- [部署 WordPress](#deploy-wordpress)
|
||||
- [访问你的新 WordPress 博客](#visit-your-new-wordpress-blog)
|
||||
- [删除并重启你的博客](#take-down-and-restart-your-blog)
|
||||
- [接下来的步骤](#next-steps)
|
||||
|
||||
|
||||
|
||||
|
||||
## 集群要求
|
||||
|
||||
|
||||
Kubernetes本质是模块化的,可以在各种环境中运行。但并不是所有集群都相同。此处是本示例的一些要求:
|
||||
* 需要 1.2 版本以上的 Kubernetes,以使用更新的特性,例如 PV Claims 和 Deployments。运行 `kubectl version` 来查看你的集群版本。
|
||||
* [Cluster DNS](https://github.com/kubernetes/dns) 将被用于服务发现。
|
||||
* 一个 [external load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer) 将被用于接入 WordPress。
|
||||
* 使用了 [Persistent Volume Claims](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)。你必须创建集群中需要的 Persistent Volumes。本示例将展示两种类型的 volume 的创建方法,但是任何类型的 volume 都是足够使用的。
|
||||
|
||||
|
||||
查阅 [Getting Started Guide](http://kubernetes.io/docs/getting-started-guides/),搭建一个集群并安装 [kubectl](http://kubernetes.io/docs/user-guide/prereqs/) 命令行工具。
|
||||
|
||||
|
||||
## 决定在哪里存储你的数据
|
||||
|
||||
|
||||
MySQL 和 WordPress 各自使用一个 [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) 来存储自己的数据。我们将使用一个 Persistent Volume Claim 来取得一个可用的持久化存储。本示例覆盖了 HostPath 和
|
||||
GCEPersistentDisk 卷类型。你可以从两者中选择一个,或者查看 [Persistent Volumes的类型](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes)。
|
||||
|
||||
|
||||
### Host Path
|
||||
|
||||
|
||||
Host paths 是映射到主机上目录的卷。**这种类型应该只用于测试目的或者单节点集群**。如果 pod 在一个新的节点上重建,数据将不会在节点之间移动。如果 pod 被删除并在一个新的节点上重建,数据将会丢失。
|
||||
|
||||
|
||||
##### SELinux
|
||||
|
||||
|
||||
在支持 selinux 的系统上,保持它为 enabled/enforcing 是最佳选择。然而,docker 容器使用 "_svirt_sandbox_file_t_" 标签类型挂载 host path,这和默认的 /tmp ("_tmp_t_") 标签类型不兼容。在 mysql 容器试图对 _/var/lib/mysql_ 执行 `chown` 时将导致权限错误。
|
||||
因此,要在一个启用 selinx 的系统上使用 host path,你应该预先创建 host path 路径(/tmp/data/)并将它的 selinux 标签类型改变为 "_svirt_sandbox_file_t_",就像下面一样:
|
||||
|
||||
```shell
|
||||
## on every node:
|
||||
mkdir -p /tmp/data
|
||||
chmod a+rwt /tmp/data # match /tmp permissions
|
||||
chcon -Rt svirt_sandbox_file_t /tmp/data
|
||||
```
|
||||
|
||||
|
||||
继续进行 host path 配置,在 Kubernetes 中使用 [local-volumes.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/local-volumes.yaml) 创建 persistent volume 对象:
|
||||
|
||||
```shell
|
||||
export KUBE_REPO=https://raw.githubusercontent.com/kubernetes/examples/master
|
||||
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/local-volumes.yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
### GCE Persistent Disk
|
||||
|
||||
|
||||
如果在 [Google Compute Engine](http://kubernetes.io/docs/getting-started-guides/gce/) 上运行集群,你可以使用这个存储选项。
|
||||
|
||||
|
||||
创建两个永久磁盘。你需要在和 Kubernetes 集群相同的 [GCE zone](https://cloud.google.com/compute/docs/zones) 中创建这些磁盘。默认的安装脚本将在 `us-central1-b` zone 中创建集群,就像你在 [config-default.sh](https://git.k8s.io/kubernetes/cluster/gce/config-default.sh) 文件中看到的。替换下面的 `<zone>` 为合适的 zone。`wordpress-1` 和 `wordpress-2` 的名字必须和 [gce-volumes.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/gce-volumes.yaml) 指定的 `pdName` 字段匹配。
|
||||
|
||||
```shell
|
||||
gcloud compute disks create --size=20GB --zone=<zone> wordpress-1
|
||||
gcloud compute disks create --size=20GB --zone=<zone> wordpress-2
|
||||
```
|
||||
|
||||
|
||||
在 Kubernetes 为这些磁盘创建 persistent volume 对象:
|
||||
|
||||
```shell
|
||||
export KUBE_REPO=https://raw.githubusercontent.com/kubernetes/examples/master
|
||||
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/gce-volumes.yaml
|
||||
```
|
||||
|
||||
|
||||
## 创建 MySQL 密码 Secret
|
||||
|
||||
|
||||
使用一个 [Secret](http://kubernetes.io/docs/user-guide/secrets/) 对象存储 MySQL 密码。首先,创建一个名为 `password.txt` 的文件(和 wordpress 示例文件在相同的文件夹),并且将你的密码保存于其中。请确保密码文件的结尾没有空行。如果你的编辑器添加了一个,开始的 `tr` 命令将会删除这个空行。然后,创建这个 Secret 对象。
|
||||
|
||||
```shell
|
||||
tr --delete '\n' <password.txt >.strippedpassword.txt && mv .strippedpassword.txt password.txt
|
||||
kubectl create secret generic mysql-pass --from-file=password.txt
|
||||
```
|
||||
|
||||
|
||||
MySQL 和 WordPress pod 配置引用了这个 secret,所以这些 pods 就可以访问它。MySQL pod 会设置数据库密码,并且 WordPress 将使用这个密码来访问数据库。
|
||||
|
||||
|
||||
## 部署 MySQL
|
||||
|
||||
<--
|
||||
Now that the persistent disks and secrets are defined, the Kubernetes
|
||||
pods can be launched. Start MySQL using
|
||||
[mysql-deployment.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/mysql-deployment.yaml).
|
||||
-->
|
||||
现在我们已经定义了永久磁盘和 secrets,可以启动 Kubernetes pods 了。使用 [mysql-deployment.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/mysql-deployment.yaml) 启动 MySQL。
|
||||
|
||||
```shell
|
||||
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/mysql-deployment.yaml
|
||||
```
|
||||
|
||||
|
||||
查看 [mysql-deployment.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/mysql-deployment.yaml),注意到我们定义了一个挂载到 `/var/lib/mysql` 的卷,然后创建了一个请求 20G 卷的 Persistent Volume Claim。这个要求可以被任何符合这个要求的卷满足,在我们的例子中,可以是上面创建的卷中的一个。
|
||||
|
||||
|
||||
再看一下 `env` 一节,我们引用上面创建的 `mysql-pass` secret 来指定密码。Secrets 可以有多组键值对。我们的只有一个键 `password.txt`,它是我们用来创建 secret 的文件名。[MySQL镜像](https://hub.docker.com/_/mysql/) 使用 `MYSQL_ROOT_PASSWORD` 环境变量设置数据库密码。
|
||||
|
||||
|
||||
在很短的时间内,新建的 pod 将达到 `Running` 状态。列出所有的 pods,查看新建的 pod 的状态。
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
wordpress-mysql-cqcf4-9q8lo 1/1 Running 0 1m
|
||||
```
|
||||
|
||||
|
||||
Kubernetes 记录每个 pod 的 stderr 和 stdout。使用 `kubectl log` 查看一个 pod 的日志。从 `get pods` 复制 pod 名字,然后:
|
||||
|
||||
```shell
|
||||
kubectl logs <pod-name>
|
||||
```
|
||||
|
||||
```
|
||||
...
|
||||
2016-02-19 16:58:05 1 [Note] InnoDB: 128 rollback segment(s) are active.
|
||||
2016-02-19 16:58:05 1 [Note] InnoDB: Waiting for purge to start
|
||||
2016-02-19 16:58:05 1 [Note] InnoDB: 5.6.29 started; log sequence number 1626007
|
||||
2016-02-19 16:58:05 1 [Note] Server hostname (bind-address): '*'; port: 3306
|
||||
2016-02-19 16:58:05 1 [Note] IPv6 is available.
|
||||
2016-02-19 16:58:05 1 [Note] - '::' resolves to '::';
|
||||
2016-02-19 16:58:05 1 [Note] Server socket created on IP: '::'.
|
||||
2016-02-19 16:58:05 1 [Warning] 'proxies_priv' entry '@ root@wordpress-mysql-cqcf4-9q8lo' ignored in --skip-name-resolve mode.
|
||||
2016-02-19 16:58:05 1 [Note] Event Scheduler: Loaded 0 events
|
||||
2016-02-19 16:58:05 1 [Note] mysqld: ready for connections.
|
||||
Version: '5.6.29' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
|
||||
```
|
||||
|
||||
|
||||
我们还需要在 [mysql-deployment.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/mysql-deployment.yaml) 中创建一个 service 以允许其它 pods 访问这个 mysql 示例。`wordpress-mysql` 名称被解析为这个 pod 的 IP。
|
||||
|
||||
|
||||
到此为止,我们创建了一个 Deployment,一个 Pod,一个 PVC,一个 Service,一个 Endpoint,两个 PV 和一个 Secret,显示如下:
|
||||
|
||||
```shell
|
||||
kubectl get deployment,pod,svc,endpoints,pvc -l app=wordpress -o wide && \
|
||||
kubectl get secret mysql-pass && \
|
||||
kubectl get pv
|
||||
```
|
||||
|
||||
```shell
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
deploy/wordpress-mysql 1 1 1 1 3m
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
po/wordpress-mysql-3040864217-40soc 1/1 Running 0 3m 172.17.0.2 127.0.0.1
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
|
||||
svc/wordpress-mysql None <none> 3306/TCP 3m app=wordpress,tier=mysql
|
||||
NAME ENDPOINTS AGE
|
||||
ep/wordpress-mysql 172.17.0.2:3306 3m
|
||||
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
||||
pvc/mysql-pv-claim Bound local-pv-2 20Gi RWO 3m
|
||||
NAME TYPE DATA AGE
|
||||
mysql-pass Opaque 1 3m
|
||||
NAME CAPACITY ACCESSMODES STATUS CLAIM REASON AGE
|
||||
local-pv-1 20Gi RWO Available 3m
|
||||
local-pv-2 20Gi RWO Bound default/mysql-pv-claim 3m
|
||||
```
|
||||
|
||||
|
||||
## 部署 WordPress
|
||||
|
||||
|
||||
接下来使用 [wordpress-deployment.yaml](https://git.k8s.io/examples/mysql-wordpress-pd/wordpress-deployment.yaml) 部署 WordPress:
|
||||
|
||||
```shell
|
||||
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/wordpress-deployment.yaml
|
||||
```
|
||||
|
||||
|
||||
我们在这里使用了许多相同的特性,比如对 persistent storage 的 volume claim 和 password 的 secret。
|
||||
|
||||
|
||||
[WordPress 镜像](https://hub.docker.com/_/wordpress/) 通过环境变量 `WORDPRESS_DB_HOST` 接收数据库的主机名。我们将这个环境变量值设置为我们创建的 MySQL
|
||||
service 的名字:`wordpress-mysql`。
|
||||
|
||||
|
||||
WordPress service 具有 `type: LoadBalancer` 的设置。这将 wordpress service 置于一个外部 IP 之下。
|
||||
|
||||
|
||||
找到你的 WordPress service 的外部 IP 地址。**为这个 service 分配一个外部 IP 地址可能会耗时一分钟左右,这取决于你的集群环境。**
|
||||
|
||||
```shell
|
||||
kubectl get services wordpress
|
||||
```
|
||||
|
||||
```
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
wordpress 10.0.0.5 1.2.3.4 80/TCP 19h
|
||||
```
|
||||
|
||||
|
||||
## 访问你的新 WordPress 博客
|
||||
|
||||
|
||||
现在,我们可以访问这个运行的 WordPress 应用。请使用你上面获取的 service 的外部 IP 地址。
|
||||
|
||||
```
|
||||
http://<external-ip>
|
||||
```
|
||||
|
||||
|
||||
你应该可以看到熟悉的 WordPress 初始页面。
|
||||
|
||||

|
||||
|
||||
|
||||
> 警告:不要在这个页面上留下你的 WordPress 设置。如果被其他用户发现,他们可能在你的实例上创建一个网站并用它来为可能有害的内容提供服务。你应该继续创建用户名密码之后的安装过程,删除你的实例,或者建立一个防火墙来限制接入。
|
||||
|
||||
|
||||
## 删除并重启你的博客
|
||||
|
||||
|
||||
建立你的 WordPress 博客并简单使用一下。然后删除它的 pods 并再次启动它们。由于使用了永久磁盘,你的博客的状态将被保留。
|
||||
|
||||
|
||||
所有的资源都被标记为 `app=wordpress`,你可以使用 label selector 轻松的删除它们:
|
||||
|
||||
```shell
|
||||
kubectl delete deployment,service -l app=wordpress
|
||||
kubectl delete secret mysql-pass
|
||||
```
|
||||
|
||||
|
||||
稍后使用原来的命令重建资源,这将会选择包含原来的完整数据的磁盘。由于我们没有删除 PV Claims,在删除我们的 pods 后,集群中没有任何一个 pod 能够 claim 它们。保留 PV Claims 也保证了重建 Pods 不会导致 PD 切换 Pods。
|
||||
|
||||
|
||||
如果你已经准备好了释放你的永久磁盘及其上的数据,请运行:
|
||||
|
||||
```shell
|
||||
kubectl delete pvc -l app=wordpress
|
||||
```
|
||||
|
||||
And then delete the volume objects themselves:
|
||||
|
||||
```shell
|
||||
kubectl delete pv local-pv-1 local-pv-2
|
||||
```
|
||||
|
||||
|
||||
或者
|
||||
|
||||
```shell
|
||||
kubectl delete pv wordpress-pv-1 wordpress-pv-2
|
||||
```
|
||||
|
||||
|
||||
## 接下来的步骤
|
||||
|
||||
* [Introspection and Debugging](http://kubernetes.io/docs/user-guide/introspection-and-debugging/)
|
||||
* [Jobs](http://kubernetes.io/docs/user-guide/jobs/) may be useful to run SQL queries.
|
||||
* [Exec](http://kubernetes.io/docs/user-guide/getting-into-containers/)
|
||||
* [Port Forwarding](http://kubernetes.io/docs/user-guide/connecting-to-applications-port-forward/)
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: local-pv-1
|
||||
labels:
|
||||
type: local
|
||||
spec:
|
||||
capacity:
|
||||
storage: 20Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
hostPath:
|
||||
path: /tmp/data/pv-1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: local-pv-2
|
||||
labels:
|
||||
type: local
|
||||
spec:
|
||||
capacity:
|
||||
storage: 20Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
hostPath:
|
||||
path: /tmp/data/pv-2
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: wordpress-mysql
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
ports:
|
||||
- port: 3306
|
||||
selector:
|
||||
app: wordpress
|
||||
tier: mysql
|
||||
clusterIP: None
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql-pv-claim
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: wordpress-mysql
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wordpress
|
||||
tier: mysql
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wordpress
|
||||
tier: mysql
|
||||
spec:
|
||||
containers:
|
||||
- image: mysql:5.6
|
||||
name: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysql-pass
|
||||
key: password
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
name: mysql
|
||||
volumeMounts:
|
||||
- name: mysql-persistent-storage
|
||||
mountPath: /var/lib/mysql
|
||||
volumes:
|
||||
- name: mysql-persistent-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql-pv-claim
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: wordpress
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: wordpress
|
||||
tier: frontend
|
||||
type: LoadBalancer
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: wp-pv-claim
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: wordpress
|
||||
labels:
|
||||
app: wordpress
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wordpress
|
||||
tier: frontend
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wordpress
|
||||
tier: frontend
|
||||
spec:
|
||||
containers:
|
||||
- image: wordpress:4.8-apache
|
||||
name: wordpress
|
||||
env:
|
||||
- name: WORDPRESS_DB_HOST
|
||||
value: wordpress-mysql
|
||||
- name: WORDPRESS_DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysql-pass
|
||||
key: password
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: wordpress
|
||||
volumeMounts:
|
||||
- name: wordpress-persistent-storage
|
||||
mountPath: /var/www/html
|
||||
volumes:
|
||||
- name: wordpress-persistent-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: wp-pv-claim
|
||||
@@ -0,0 +1,44 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
name: web
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: web
|
||||
spec:
|
||||
serviceName: "nginx"
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: k8s.gcr.io/nginx-slim:0.8
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: web
|
||||
volumeMounts:
|
||||
- name: www
|
||||
mountPath: /usr/share/nginx/html
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: www
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
name: web
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: web
|
||||
spec:
|
||||
serviceName: "nginx"
|
||||
podManagementPolicy: "Parallel"
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: k8s.gcr.io/nginx-slim:0.8
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: web
|
||||
volumeMounts:
|
||||
- name: www
|
||||
mountPath: /usr/share/nginx/html
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: www
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zk-headless
|
||||
labels:
|
||||
app: zk-headless
|
||||
spec:
|
||||
ports:
|
||||
- port: 2888
|
||||
name: server
|
||||
- port: 3888
|
||||
name: leader-election
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: zk
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: zk-config
|
||||
data:
|
||||
ensemble: "zk-0;zk-1;zk-2"
|
||||
jvm.heap: "2G"
|
||||
tick: "2000"
|
||||
init: "10"
|
||||
sync: "5"
|
||||
client.cnxns: "60"
|
||||
snap.retain: "3"
|
||||
purge.interval: "1"
|
||||
---
|
||||
apiVersion: policy/v1beta1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: zk-budget
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: zk
|
||||
minAvailable: 2
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: zk
|
||||
spec:
|
||||
serviceName: zk-headless
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: zk
|
||||
annotations:
|
||||
pod.alpha.kubernetes.io/initialized: "true"
|
||||
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: "app"
|
||||
operator: In
|
||||
values:
|
||||
- zk-headless
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
containers:
|
||||
- name: k8szk
|
||||
imagePullPolicy: Always
|
||||
image: gcr.io/google_samples/k8szk:v1
|
||||
resources:
|
||||
requests:
|
||||
memory: "4Gi"
|
||||
cpu: "1"
|
||||
ports:
|
||||
- containerPort: 2181
|
||||
name: client
|
||||
- containerPort: 2888
|
||||
name: server
|
||||
- containerPort: 3888
|
||||
name: leader-election
|
||||
env:
|
||||
- name : ZK_ENSEMBLE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: ensemble
|
||||
- name : ZK_HEAP_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: jvm.heap
|
||||
- name : ZK_TICK_TIME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: tick
|
||||
- name : ZK_INIT_LIMIT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: init
|
||||
- name : ZK_SYNC_LIMIT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: tick
|
||||
- name : ZK_MAX_CLIENT_CNXNS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: client.cnxns
|
||||
- name: ZK_SNAP_RETAIN_COUNT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: snap.retain
|
||||
- name: ZK_PURGE_INTERVAL
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: zk-config
|
||||
key: purge.interval
|
||||
- name: ZK_CLIENT_PORT
|
||||
value: "2181"
|
||||
- name: ZK_SERVER_PORT
|
||||
value: "2888"
|
||||
- name: ZK_ELECTION_PORT
|
||||
value: "3888"
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- zkGenConfig.sh && zkServer.sh start-foreground
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- "zkOk.sh"
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 5
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- "zkOk.sh"
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 5
|
||||
volumeMounts:
|
||||
- name: datadir
|
||||
mountPath: /var/lib/zookeeper
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: datadir
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
Reference in New Issue
Block a user