Docker AWS教程

您所在的位置:网站首页 k8s教程哪个好 Docker AWS教程

Docker AWS教程

2023-04-13 08:35| 来源: 网络整理| 查看: 265

Kubernetes 是一个流行的开源容器管理平台,最初由谷歌开发,它基于谷歌自己的内部博格(https://Kubernetes . io/blog/2015/04/博格-前身到 kubernetes/ )容器平台。Kubernetes 利用了谷歌在大规模运行容器方面的丰富经验,现在随着 aws 弹性 Kubernetes 服务(EKS)的发布,所有主要的云平台提供商都支持它。EKS 提供了一个托管的 Kubernetes 集群,您可以将容器应用部署到其中,而不必担心日常运营开销和集群管理的复杂性。AWS 已经完成了建立一个健壮且可扩展的平台的所有繁重工作,使其比以往任何时候都更容易与 Kubernetes 一起启动和运行。

在本章中,您将了解 Kubernetes 的世界,我们将研究如何配置 Kubernetes,以确保我们能够成功部署和操作我们通过本书使用的示例应用,然后在 AWS 中建立一个 EKS 集群,您将使用您在本地开发的配置部署应用。这将为作为应用所有者的您如何将容器工作负载部署到 Kubernetes,以及如何快速启动并运行 EKS 提供实际的见解。

我们将首先了解如何在本地使用该平台,使用 Docker for Mac 和 Docker for Windows 现在为 Kubernetes 提供的本机支持。您可以开箱即用地启动本地单节点群集,从而减少启动和运行本地环境通常需要的大量手动配置。您将学习如何创建在 Kubernetes 中运行示例应用所需的各种类型的资源,解决关键的操作挑战,例如为应用数据库提供持久存储、机密管理,以及运行一次性任务,例如数据库迁移。

一旦您建立了一个工作配置,让示例应用在 Kubernetes 本地启动并运行,我们将把注意力转向从 EKS 开始,创建一个 EKS 集群,并建立一个 EC2 自动扩展组,在该组中管理运行您的容器工作负载的工作节点。您将学习如何从本地环境设置对集群的访问,并继续部署 Kubernetes Dashboard,它提供了丰富的管理用户界面,您可以从中部署和管理应用。最后,您将设置与其他 AWS 服务的集成,包括弹性块存储(EBS)和弹性负载平衡(ELB),并继续将示例应用部署到您的 EKS 集群。

本章将涵盖以下主题:

Kubernetes 的概论 不可思议的建筑 Kubernetes 入门 使用 docker desktop 安装 kubricks 创建核心 Kubernetes 资源,包括吊舱、部署和服务 创建永久卷 创造永恒的机密 运行非循环作业 创建 EKS 集群 建立对 EKS 集群的访问 将应用部署到 EKS 技术要求

以下是本章的技术要求:

对 AWS 帐户的管理员访问权限 根据第 3 章中的说明配置的本地 AWS 配置文件 AWS CLI 版本 1.15.71 或更高版本 Docker 18.06 或更高 Docker 写作 1.22 或更高 GNU Make 3.82 或更高版本 本章假设您已经完成了本书前面的所有章节

以下 GitHub URL 包含本章使用的代码示例:https://GitHub . com/docker-in-AWS/docker-in-AWS/tree/master/ch17。

查看以下视频,了解《行动守则》: http://bit.ly/2LyGtSY

Kubernetes 的概论

Kubernetes 是由 Google 在 2014 年开源的开源容器管理平台,2015 年以其 1.0 版本实现量产准备。在三年的时间里,它已经成为最受欢迎的容器管理平台,并且非常受希望将其应用作为容器工作负载运行的大型组织的欢迎。Kubernetes 是 github 上最受欢迎的开源项目之一(https://GitHub . com/cncf/velocity/blob/master/docs/top30 chart creation . MD),根据 [Redmonk]),根据 Redmonk 的数据,截至 2017 年末,Kubernetes 在财富 100 强公司中的使用率为 54%。 Kubernetes 的主要功能包括:

平台不可知 : Kubernetes 可以在任何地方运行,从您的本地机器到您的数据中心,以及 AWS、Azure 和 Google Cloud 等云提供商,它们现在都提供集成的托管 Kubernetes 产品。 开源 : Kubernetes 最大的优势在于它的社区性和开源性,这让 Kubernetes 成为了这个星球上领先的开源项目之一。主要组织和供应商正在投入大量时间和资源为平台做贡献,确保整个社区从这些持续的增强中受益。 谱系 : Kubernetes 的根源来自谷歌内部的博格平台,该平台从 2000 年代初就开始大规模运行容器。谷歌是容器技术的先驱之一,毫无疑问是容器的最大采用者之一——早在 2014 年,谷歌就表示,他们每周运行 20 亿个容器,而当时大多数企业只是通过一个名为 Docker 的新项目才听说容器,这个项目正在席卷科技行业。这种血统和传统确保了谷歌多年来大规模运行容器的经验被封装在 Kubernetes 平台中。 生产级容器管理功能 : Kubernetes 提供了所有您期望看到并将在其他竞争平台上遇到的容器管理功能。这包括集群管理、多主机网络、可插拔存储、运行状况检查、服务发现和负载平衡、服务扩展和滚动更新、所需的阶段配置、基于角色的访问控制以及机密管理等。所有这些功能都是以模块化构造块的方式实现的,允许您调整系统以满足组织的特定要求,这也是 Kubernetes 现在被认为是企业级容器管理的黄金标准的原因之一。 库伯内斯诉 Docker

在前一章中,我提供了我自己对 Docker Swarm 和 Kubernetes 的想法,在这里我将继续,这一次更多地关注为什么你会选择 Kubernetes 而不是 Docker Swarm。当您完成这一章时,应该很明显,Kubernetes 有一个更复杂的体系结构,这意味着有一个更高的学习曲线,我在这一章中介绍的只是 Kubernetes 可能做到的事情的表面。也就是说,一旦你了解了这些概念,至少从我的角度来看,你应该看到 Kubernetes 最终更强大,具有更大的灵活性,可以说,Kubernetes 肯定比 Docker Swarm 感觉更“企业级”,有更多的旋钮可以根据您的特定需求定制 Kubernetes。

与 Docker Swarm 和其他竞争对手相比,Kubernetes 最大的优势可能是它的社区,这一点非常重要,这意味着在更广泛的 Kubernetes 社区和生态系统中,可以很容易地找到关于您能想到的几乎任何配置场景的信息。Kubernetes 运动的背后一直有很大的动力,而随着领先的供应商和提供商(如 AWS)用自己的产品和解决方案拥抱 Kubernetes,这种动力似乎只会越来越大。

不可思议的建筑

在架构上,Kubernetes 以集群的形式组织自己,其中主节点形成集群控制平面,工作节点运行您的实际容器工作负载:

Kubernetes architecture

在每个主节点中,存在许多组件:

kube-apiserver :这暴露了 Kubernetes API,是你用来与 Kubernetes 控制平面交互的前端组件。 etcd :这提供了一个跨集群的分布式高可用性密钥/值存储,用于存储 Kubernetes 配置和操作数据。 kube-scheduler :这将 pods 调度到工作节点上,同时考虑资源需求、约束、数据局部性和其他因素。稍后您将了解更多关于 pods 的信息,但是现在您可以将它们看作是相关容器和卷的集合,它们需要一起创建、更新和部署。 kube-controller-manager :负责管理控制器,控制器由多个组件组成,用于检测您的节点何时停止运行,确保您的 pods 有正确数量的实例或副本正在运行,为您的 pods 中运行的应用发布服务端点,并管理集群的服务帐户和 API 访问令牌。 云控制器管理器:这提供了与底层云提供商交互的控制器,使云提供商能够支持特定于其平台的功能。云控制器的示例包括创建、更新和删除云提供商负载平衡器的服务控制器,以及创建、连接、分离和删除云提供商支持的各种存储卷技术的卷控制器。 附加组件:有许多附加组件可以扩展集群的功能。这些以提供集群功能的吊舱和服务的形式运行。大多数安装中通常部署的一个附加组件是群集 DNS 附加组件,它为群集上运行的服务和 pod 提供自动 DNS 命名和解析。

在所有节点上,都存在以下组件:

kubelet :在集群中的每个节点上运行的代理,它确保 pod 中的所有容器都运行正常。kubelet 还可以收集可以发布到监控系统的容器度量。 kube-proxy :管理网络通信、端口映射和每个节点上所需的路由规则,以支持 Kubernetes 支持的各种服务抽象。 容器运行时:这提供了运行容器的容器引擎。支持的最流行的容器运行时是 Docker,但是在容器运行时下,如 rkt (Rocket)或任何 OCI 运行时规范的实现都可以得到支持。 pod:pod 是部署容器应用的核心工作单元。每个容器由一个或多个容器和相关资源以及一个网络接口组成,这意味着给定容器中的每个容器共享相同的网络栈。

请注意,工作节点只运行前面直接列出的组件,而主节点运行我们到目前为止讨论过的所有组件,这允许主节点也为单节点集群等场景运行容器工作负载。 Kubernetes 还提供了一个名为 kubectl 的客户端组件,它提供了通过 Kubernetes API 管理集群的能力。 kubectl 在 Windows、macOS 和 Linux 上受支持,允许您轻松管理多个集群并在它们之间切换,既可以本地运行,也可以远程运行。

Kubernetes 入门

现在,您已经简单地了解了 Kubernetes,让我们专注于在您的本地环境中与 Kubernetes 一起启动和运行。

在本书的前面,当您设置本地开发环境时,如果您使用的是 macOS 或 Windows,则安装了 Docker Desktop 的社区版(CE)版本(Docker for Mac 或 Docker for Windows,在本章中我可能统称为 Docker Desktop),其中包括对 Kubernetes 的本机支持。 If you are using a variant of Docker for Mac/Windows that does not support Kubernetes, or are using Linux, you can install minikube by following the instructions at https://github.com/kubernetes/minikube. Most of the examples included in this section should work with minikube, although features such as load balancing and dynamic host path provisioning may not be directly supported and require some additional configuration.

要启用 Kubernetes,请在本地 Docker 桌面设置中选择 Kubernetes ,并选中启用 Kubernetes 选项。单击应用后,将安装 Kubernetes,并需要几分钟时间启动和运行:

Enabling Kubernetes using Docker for Mac Docker Desktop 还会自动为您安装和配置 Kubernetes 命令行实用程序kubectl,可用于验证您的安装:

> kubectl get nodes NAME STATUS ROLES AGE VERSION docker-for-desktop Ready master 1m v1.10.3

如果您将 Docker for Windows 与 Linux 子系统 for Windows 结合使用,您将需要通过运行以下命令将kubectl安装到子系统中(有关更多详细信息,请参见https://kubernetes . io/docs/tasks/tools/install-kube CTL/# install-kube CTL-binary-via-native-package-management):

sudo apt-get update && sudo apt-get install -y apt-transport-https curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - sudo touch /etc/apt/sources.list.d/kubernetes.list echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubectl

安装kubectl后,如果您之前将您的 Linux 子系统主文件夹更改为您的 Windows 主文件夹,您现在应该能够与本地 Kubernetes 集群交互,而无需进一步配置。

如果您的主文件夹不同于 Windows 主文件夹(默认情况下是这样),那么您需要设置一个指向 Windows 主文件夹中kubectl配置文件的符号链接,之后您应该能够使用kubectl与本地 Kubernetes 安装进行交互:

## Only required if Linux Subsystem home folder is different from Windows home folder $ mkdir -p ~/.kube $ ln -s /mnt/c/Users//.kube/config ~/.kube/config $ kubectl get nodes NAME STATUS ROLES AGE VERSION docker-for-desktop Ready master 1m v1.10.3

The Linux subsytem for Windows also allows you to run Windows command-line programs, so alternatively you can run kubectl.exe to invoke the Windows kubectl component.

创建一个吊舱

在 Kubernetes 中,您将您的应用部署为 pods ,它们指的是一个或多个彼此密切相关的容器和其他资源,并共同表示您的应用。一个吊舱是 Kubernetes 的核心工作单元,在概念上类似于一个 ECS 任务定义,尽管在引擎盖下它们以完全不同的方式工作。 A common shorthand code for Kubernetes is k8s, where the “ubernete” portion of the name Kubernetes is replaced with the digit 8, representing the number of characters in “ubernete”.

在我们创建第一个 pod 之前,让我们在 todo back and 存储库中建立一个名为k8s的文件夹,该文件夹将保存 todo back and 应用的所有 Kubernetes 配置,然后创建一个名为app的文件夹,该文件夹将存储与核心 todo back and 应用相关的所有资源定义:

todobackend> mkdir -p k8s/app todobackend> touch k8s/app/deployment.yaml

下面的代码演示了 todobackend 应用的基本 pod 定义,我们将把它保存到k8s/app/deployment.yaml文件中:

apiVersion: v1 kind: Pod metadata: name: todobackend labels: app: todobackend spec: containers: - name: todobackend image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent command: - uwsgi - --http=0.0.0.0:8000 - --module=todobackend.wsgi - --master - --die-on-term - --processes=4 - --threads=2 - --check-static=/public env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release

pod 配置文件的格式很容易理解,一般来说,如果您习惯于使用 Docker Compose 定义容器,那么您看到的大多数参数都会映射到同名的参数。一个容易引起混淆的重要区别是command参数——在 Kubernetes 中,该参数相当于 Docker Compose 服务规范中的ENTRYPOINT Dockerfile 指令和entrypoint参数,而 Kubernetes 中的args参数相当于 CMD 指令(Dockerfile)和command服务参数(Docker Compose)。这意味着在前面的配置中,我们的容器中的默认入口点脚本被绕过,取而代之的是 uwsgi web 服务器将直接运行。 IfNotPresent的imagePullPolicy属性值将 Kubernetes 配置为仅在本地 Docker Engine 注册表中没有映像的情况下拉取一个映像,这意味着在尝试创建 pod 之前,您必须确保已运行现有的 todobackend Docker Compose 工作流来本地构建和标记 todo back and 映像。这是必需的,因为当您在 AWS EC2 实例上运行 Kubernetes 时,Kubernetes 仅包括对 ECR 的本机支持,而当您在 AWS 之外运行 Kubernetes 时,Kubernetes 不支持 ECR。 There are a number of third-party plugins available that allow you to manage AWS credentials and pull ECR images. A popular example can be found at https://github.com/upmc-enterprises/registry-creds

要创建我们的 pod 并验证它是否正在运行,您可以运行kubectl apply命令,其中-f标志引用您刚刚创建的部署文件,后跟kubectl get pods命令:

> kubectl apply -f k8s/app/deployment.yaml pod "todobackend" created > kubectl get pods NAME READY STATUS RESTARTS AGE todobackend 1/1 Running 0 7s > docker ps --format "" k8s_todobackend_todobackend_default_1b436412-9001-11e8-b7af-025000000001_0 > docker ps --format ": {{ .Command }} ({{ .Status }})" fc0c8acdd438: "uwsgi --http=0.0.0.…" (Up 16 seconds) > docker ps --format " Ports: {{ .Ports }}" fc0c8acdd438 Ports:

您可以看到 pod 的状态是Running,并且一个容器已经被部署到在您的本地 Docker Desktop 环境中运行的单节点 Kubernetes 集群中。需要注意的一点是,已经部署的 todobackend 容器没有与外部世界通信的手段,因为没有从 pod 及其关联容器发布的网络端口。 Kubernetes 的一个有趣的方面是,您可以使用 Kubernetes API 与您的豆荚进行交互。为了演示这一点,首先运行kubectl proxy命令,该命令设置一个本地 HTTP 代理,该代理通过一个普通的旧 HTTP 接口公开 API:

> kubectl proxy Starting to serve on 127.0.0.1:8001

现在,您可以通过网址http://localhost:8001/api/v1/namespaces/default/pods/todobackend:8000/proxy/访问吊舱上的容器端口 8000:

Running the kubectl proxy

如您所见,todobackend 应用正在运行,尽管它缺少静态内容,因为我们还没有生成它。还要注意,页面底部的 todos 链接(http://localhost:8001/todos)是无效的,因为 todobackend 应用不知道通过代理访问应用所调用的 API 路径。 Kubernetes 的另一个有趣的特性是能够通过运行kubectl port-forward命令将 Kubernetes 客户端的端口公开给应用,该命令在客户端发布一个本地端口,并使用 Kubernetes API 将其连接到指定的 pod:

> kubectl proxy Starting to serve on 127.0.0.1:8001 ^C > kubectl port-forward todobackend 8000:8000 Forwarding from 127.0.0.1:8000 -> 8000 Forwarding from [::1]:8000 -> 8000 Handling connection for 8000

如果您现在尝试访问http://localhost:8000,您应该会看到 todosbackend 主页,并且页面底部的 todo 链接现在应该可以访问:

Accessing a port forwarded pod

您可以再次看到,我们的应用没有处于完全正常的状态,因为我们还没有配置任何数据库设置。

创建部署

虽然我们已经能够发布我们的 todobackend 应用,但是我们用来发布的机制并不适合现实世界的生产使用,只对有限的本地开发场景真正有用。

在现实世界中运行我们的应用的一个关键要求是能够增加或减少应用容器的实例或副本的数量。为了实现这一点,Kubernetes 支持一类称为控制器的资源,它们负责协调、组织和管理给定 pod 的多个副本。一种流行的控制器类型是部署资源,顾名思义,它包括支持创建和更新新版本的 pods,以及滚动升级和支持部署失败时的回滚等功能。

以下示例演示了更新todobackend存储库中的k8s/app/deployment.yaml文件以定义部署资源:

apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend spec: replicas: 2 selector: matchLabels: app: todobackend template: metadata: labels: app: todobackend spec: containers: - name: todobackend image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 8000 livenessProbe: httpGet: port: 8000 command: - uwsgi - --http=0.0.0.0:8000 - --module=todobackend.wsgi - --master - --die-on-term - --processes=4 - --threads=2 - --check-static=/public env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release

我们将之前的 pod 资源更新为现在的部署资源,顶层spec属性(即spec.template)的template属性内联定义了应该部署的 pod。部署和 Kubernetes 的一个关键概念通常是使用基于集合的标签选择器匹配(https://Kubernetes . io/docs/concepts/overview/work-with-objects/labels/# label-selectors)来确定部署适用的资源或 pods。在前面的示例中,部署资源spec指定了两个replicas,并使用selectors.matchLabels将部署匹配到包含标签app和值todobackend的 pod。这是一个简单而强大的范例,允许您以灵活且松散耦合的方式创建自己的结构和资源之间的关系。请注意,我们还向容器定义中添加了readinessProbe和livenessProbe属性,它们分别创建了就绪探测和活动探测。就绪探测器定义了 Kubernetes 应该执行的操作,以确定容器是否就绪,而活跃度探测器用于确定容器是否仍然健康。在前面的示例中,就绪探测器使用对端口 8000 的 HTTP GET 请求来确定部署控制器何时应该允许将连接转发到容器,而活跃度探测器用于在容器不再响应活跃度探测器的情况下重新启动容器。请参考https://kubernetes . io/docs/tasks/configure-pod-container/configure-liveness-ready-probes/了解不同类型的探针及其使用方法的更多信息。

要创建新的部署资源,我们可以首先移除现有的 pod,然后使用kubectl在todobackend存储库中应用k8s/app/deployment.yaml文件:

> kubectl delete pods/todobackend pod "todobackend" deleted > kubectl apply -f k8s/app/deployment.yaml deployment.apps "todobackend" created> kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE todobackend 2 2 2 2 12s> kubectl get pods NAME READY STATUS RESTARTS AGE todobackend-7869d9965f-lh944 1/1 Running 0 17s todobackend-7869d9965f-v986s 1/1 Running 0 17s

创建部署后,您可以看到配置数量的副本以两个单元的形式部署,每个单元都有一个唯一的名称。一旦您配置的就绪探测器成功,每个吊舱的状态将转换为就绪。

创建服务

此时,我们已经为应用定义了一个 pod,并使用一个部署资源部署了应用的多个副本,现在我们需要确保外部客户端可以连接到我们的应用。假设我们的应用有多个副本在运行,我们需要一个能够提供稳定的服务端点、跟踪每个副本的位置并在所有副本之间负载平衡传入连接的组件。 服务是提供此类功能的 Kubernetes 资源,其中每个服务都被分配了一个虚拟 IP 地址,该地址可用于访问给定的一组 pod,并且基于 iptables 规则,到虚拟 IP 地址的传入连接被负载平衡到每个 pod 副本,iptables 规则通过称为 kube-proxy 的标准 Kubernetes 系统资源进行管理和更新:

Services and endpoints in Kubernetes

在上图中,一个客户端 pod 正试图使用端口80 ( 10.1.1.1:80)上的虚拟 IP 地址10.1.1.1与应用 pod 通信。请注意,服务虚拟 IP 地址是在集群中的每个节点上发布的,其中 kube-proxy 组件负责更新 iptables 规则,该规则选择客户端连接应该以循环方式路由到的适当端点。因为虚拟 IP 地址发布在集群中的每个节点上,所以任何节点上的任何客户端都可以与服务通信,并且流量以均匀的方式分布在集群中。

现在,您已经对服务的工作原理有了较高的理解,让我们在位于todobackend存储库中的k8s/app/deployment.yaml文件中定义一个新的服务:

apiVersion: v1 kind: Service metadata: name: todobackend spec: selector: app: todobackend ports: - protocol: TCP port: 80 targetPort: 8000 apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend ... ...

请注意,您可以在单个 YAML 文件中定义多个资源,方法是使用---分隔符分隔每个资源,并且我们可以创建一个名为 todobackend 的服务,该服务使用标签匹配将服务绑定到标签为app=todobackend的任何 pods。在spec.ports部分,我们将端口 80 配置为服务的传入或监听端口,这将对每个 pod 上的 8000 个targetPort连接进行负载平衡。

有了我们服务的定义,您现在可以使用kubectl apply命令部署服务:

> kubectl apply -f k8s/app/deployment.yaml service "todobackend" created deployment.apps "todobackend" unchanged > kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 8h todobackend ClusterIP 10.103.210.17 80/TCP 10s > kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.65.3:6443 1d todobackend 10.1.0.27:8000,10.1.0.30:8000 16h

您可以使用kubectl get svc命令查看当前服务,并注意到每个服务都包括一个唯一的集群 IP 地址,这是集群中其他资源可以用来与服务相关联的 pod 通信的虚拟 IP 地址。kubectl get endpoints命令显示了与每个服务相关联的实际端点,您可以看到到10.103.210.17:80的todobackend服务虚拟 IP 地址的连接将被负载平衡到10.1.0.27:8000和10.1.0.30:8000。

每个服务也以..svc.cluster.local的形式分配一个唯一的 DNS 名称。Kubernetes 中的默认命名空间被称为default,因此对于我们的 todobackend 应用,它将被分配一个名称todobackend.default.svc.cluster.local,您可以使用kubectl run命令验证该名称在集群中是否可达:

> kubectl run dig --image=googlecontainer/dnsutils --restart=Never --rm=true --tty --stdin \ --command -- dig todobackend a +search +noall +answer ; DiG 9.8.4-rpz2+rl005.12-P1 todobackend a +search +noall +answer ;; global options: +cmd todobackend.default.svc.cluster.local. 30 IN A 10.103.210.17

在前面的例子中,您可以简单地查询 todo backnd,因为 Kubernetes 将 DNS 搜索域发送到.svc.cluster.local(在我们的用例中为default.svc.cluster.local),您可以看到这解析为 todo backnd 服务的集群 IP 地址。

需要注意的是,集群 IP 地址只能在 Kubernetes 集群内访问,如果没有进一步的配置,我们无法从外部访问该服务。

公开服务

为了允许外部客户端和系统与 Kubernetes 服务进行通信,您必须向外界公开该服务。在真正的 Kubernetes 风格中,有多种选项可以实现这一点,这些选项由 Kubernetes ServiceTypes控制:

节点端口:该服务类型将每个 Kubernetes 节点上的外部端口映射到为该服务配置的内部集群 IP 和端口。这为您的服务创建了几个外部连接点,这些连接点可能会随着节点的变化而变化,从而很难创建稳定的外部服务端点。 负载平衡器:代表一个外部专用的第 4 层(TCP 或 UDP)负载平衡器,专门映射到您的服务。实际部署的负载平衡器取决于您的目标平台,例如,使用 AWS,会创建一个经典的弹性负载平衡器。这是一个非常受欢迎的选项,但是一个显著的限制是每个服务创建一个负载平衡器,这意味着如果您有很多服务,这个选项可能会变得非常昂贵。 入口:这是一个共享的第 7 层(HTTP)负载均衡器资源,其工作方式类似于 AWS 应用负载均衡器,在 AWS 应用负载均衡器中,到单个 HTTP/HTTPS 端点的连接可以基于主机头或 URL 路径模式路由到多个服务。这被认为是基于 HTTP 的服务的最佳选择,因为您可以跨多个服务共享一个负载平衡器。

向外部发布服务的最常见方法是使用负载平衡器方法,如下图所示:

Load balancing in Kubernetes

外部负载平衡器发布客户端将连接到的外部服务端点,在前面的示例中是192.0.2.43:80。负载平衡器服务端点将与群集中具有与服务相关联的活动 pod 的节点相关联,每个节点都有一个通过 kube-proxy 组件设置的节点端口映射。然后,节点端口映射被映射到节点上的每个本地端点,从而允许流量在整个集群中高效且均匀地进行负载平衡。 For communications from internal clients within the cluster, communications still take place using the service cluster IP address, as described earlier in this chapter.

在本章的后面,我们将看到如何将 AWS 负载平衡器与 EKS 集成,但是目前您的本地 Docker Desktop 环境包括对其自己的负载平衡器资源的支持,该资源在您的主机上为您的服务发布一个外部端点。向服务添加外部负载平衡器非常简单,如下例所示,我们在 todobackend 存储库中修改k8s/app/deployments.yaml文件的配置:

apiVersion: v1 kind: Service metadata: name: todobackend spec: selector: app: todobackend ports: - protocol: TCP port: 80 targetPort: 8000 type: LoadBalancer --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend ... ...

为您的环境部署合适的负载平衡器所需要的只是将spec.type属性设置为LoadBalancer,Kubernetes 将自动创建一个外部负载平衡器。您可以通过应用更新的配置并运行kubectl get svc命令来测试这一点:

> kubectl apply -f k8s/app/deployment.yaml service "todobackend" configured deployment.apps "todobackend" unchanged > kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 8h todobackend LoadBalancer 10.103.210.17 localhost 80:31417/TCP 10s > curl localhost

请注意,kubectl get svc输出现在显示 todobackend 服务的外部 IP 地址是 localhost (localhost 总是您的 Docker 客户端在使用 Docker Desktop 时可以到达的外部接口),并且它是在端口 80 上向外发布的,您可以通过运行curl localhost命令来验证它是否为真。外部端口映射到单节点集群上的端口 31417,这是 kube-proxy 组件监听的端口,以便支持我们前面描述的负载平衡器体系结构。

为您的豆荚增加体积

现在,我们已经了解了如何在 Kubernetes 集群内部以及向外部发布我们的应用,我们可以通过添加对 todo back and 应用的各种部署活动和依赖关系的支持,专注于使 todo back and 应用完全正常运行。

我们将首先解决为 todo back and 应用提供静态内容的问题——正如您在前面几章中所知道的,我们需要运行一个 collectstatic 任务,以确保静态内容可用于todo back and应用,并且这应该在部署todo back and应用的任何时候运行。 collectstatic 任务需要将静态内容写入一个卷,然后由主应用容器装载,因此让我们讨论如何将卷添加到 Kubernetes pods 中。 Kubernetes 有一个强大的存储子系统,支持多种卷类型,您可以在https://kubernetes . io/docs/concepts/storage/volumes/# type-of-volumes上了解更多。对于 collectstatic 用例来说, emptyDir 卷类型是合适的,它是一个遵循每个 pod 生命周期的卷——它是随 pod 动态创建和销毁的——因此它适合作为一个临时存储类型用于缓存和提供静态内容等用例,这些静态内容可以在 pod 创建时轻松地重新生成。

以下示例演示了如何向k8s/app/deployment.yaml文件添加公共emptyDir卷:

... ... --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend spec: replicas: 2 selector: matchLabels: app: todobackend template: metadata: labels: app: todobackend spec: securityContext: fsGroup: 1000 volumes: - name: public emptyDir: containers: - name: todobackend image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 8000 livenessProbe: httpGet: port: 8000 volumeMounts: - name: public mountPath: /public command: - uwsgi - --http=0.0.0.0:8000 - --module=todobackend.wsgi - --master - --die-on-term - --processes=4 - --threads=2 - --check-static=/public env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release

我们在 pod 模板的spec.Volumes属性中定义一个名为public的卷,然后使用 todobackend 容器定义中的volumeMounts属性将public卷挂载到/public。我们用例的一个重要配置要求是设置spec.securityContext.fsGroup属性,该属性定义了组标识,该组标识将被配置为 pod 中任何文件系统挂载的组所有者。我们将该值设置为1000;回想一下前面几章,todobackend 映像作为app用户运行,该用户/组 ID 为 1000。该配置确保 todobackend 容器能够读写静态内容到public卷。

如果您现在部署您的配置更改,您应该能够使用kubectl exec命令检查 todobackend 容器文件系统,并验证我们可以读写/public挂载:

> kubectl apply -f k8s/app/deployment.yaml service "todobackend" unchanged deployment.apps "todobackend" configured > kubectl exec $(kubectl get pods -l app=todobackend -o=jsonpath='{.items[0].metadata.name}') \ -it bash bash-4.4$ touch /public/foo bash-4.4$ ls -l /public/foo -rw-r--r-- 1 app app 0 Jul 26 11:28 /public/foo bash-4.4$ rm /public/foo

kubectl exec命令类似于docker exec命令,因为它允许您在当前运行的 pod 容器内执行命令。这个命令必须引用 pod 的名称,我们使用kubectl get pods命令和一个 JSON 路径查询来提取这个名称。如您所见,至容器内的app用户能够读写/public底座。

将初始化容器添加到您的豆荚中

有了用于静态内容的临时卷,我们现在可以专注于调度收集静态任务来为我们的应用生成静态内容。Kubernetes 支持初始化容器,这是 pod 中的一种特殊类型的容器,在主应用容器启动之前执行。Kubernetes 将确保您的 init 容器运行到完成,并在启动应用之前成功完成,如果您指定多个 init 容器,Kubernetes 将按顺序逐一执行它们,直到所有 init 容器都完成。

下面的代码演示了向k8s/app/deployment.yaml文件添加一个初始化容器:

... ... --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend spec: replicas: 2 selector: matchLabels: app: todobackend template: metadata: labels: app: todobackend spec: securityContext: fsGroup: 1000 volumes: - name: public emptyDir: initContainers: - name: collectstatic image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent volumeMounts: - name: public mountPath: /public command: ["python3","manage.py","collectstatic","--no-input"] env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release containers: ... ...

现在,您可以部署您的更改,并使用kubectl logs命令验证 collectstatic init 容器是否成功执行:

> kubectl apply -f k8s/app/deployment.yaml service "todobackend" unchanged deployment.apps "todobackend" configured > kubectl logs $(kubectl get pods -l app=todobackend -o=jsonpath='{.items[0].metadata.name}') \ -c collectstatic Copying '/usr/lib/python3.6/site-packages/django/contrib/admin/static/admin/fonts/README.txt' ... ... 159 static files copied to '/public/static'.

如果您现在在浏览器中浏览到http://localhost,您应该能够验证静态内容现在是否正确呈现:

The todobackend application with correct static content

添加数据库服务

让至应用完全运行的下一步是添加一个数据库服务,该服务将托管至应用数据库。我们将在我们的 Kubernetes 集群中运行这个服务,但是在 AWS 的实际生产用例中,我通常建议使用关系数据库服务(RDS)。

定义数据库服务需要两个主要的配置任务:

创建持久存储 创建数据库服务 创建持久存储

我们的数据库服务的一个关键需求是持久存储,对于我们的单节点本地 Kubernetes 开发环境来说, hostPath 卷类型代表了提供简单持久存储需求的标准选项。

虽然您可以通过直接在卷定义中指定路径来非常容易地创建一个 hostPath 卷(参见位于https://kubernetes . io/docs/concepts/storage/volumes/# hostPath的示例 pod 定义),但是这种方法的一个问题是,它会对底层卷类型产生硬依赖,并且如果您想要删除 pod 和与卷相关联的数据,还需要手动清理。 Docker Desktop Kubernetes 支持的一个非常有用的特性是包含一个名为docker.io/hostpath的动态卷供应器,它会自动为您创建类型为 hostPath 的卷,该卷可通过默认的存储类获得,您可以通过运行kubectl get sc命令来查看:

> kubectl get sc NAME PROVISIONER AGE hostpath (default) docker.io/hostpath 2d

存储类提供了对底层卷类型的抽象,这意味着您的 pods 可以从特定类请求存储。这包括一般要求,如卷大小,而不需要担心底层卷类型。在 Docker Desktop 的情况下,默认存储类是开箱即用的,它使用 hostPath 卷类型来提供存储请求。

但是,稍后当我们使用 EKS 在 AWS 中设置 Kubernetes 集群时,我们将配置一个默认存储类,该类使用 AWS 弹性块存储(EBS)作为底层卷类型。采用这种方法意味着我们不需要更改 pod 定义,因为我们将在每个环境中引用相同的存储类。 If you are using minikube, a dynamic provisioner called k8s.io/minikube-hostpath provides similar functionality to the Docker hostpath provisioner, but mounts volumes under /tmp/hostpath-provisioner.

要使用存储类,而不是直接用 pod 定义指定卷类型,您需要创建一个持久卷声明,它提供了卷大小和访问模式等存储要求的逻辑定义。让我们定义一个持久的卷声明,但是在此之前,我们需要在 todobackend 存储库中建立一个名为k8s/db的新文件夹,它将存储我们的数据库服务配置:

todobackend> mkdir -p k8s/db todobackend> touch k8s/db/storage.yaml

在这个文件夹中,我们将创建一个名为k8s/db/storage.yaml的文件,其中我们将定义一个持久卷声明:

kind: PersistentVolumeClaim apiVersion: v1 metadata: name: todobackend-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi

我们在一个专用文件中创建索赔(称为todobackend-data),因为这将允许我们独立管理索赔的生命周期。上例中没有包括的一个属性是spec.storageClassName属性——如果省略该属性,将使用默认存储类,但是请记住,您可以创建和引用自己的存储类。spec.accessModes属性指定了应该如何装载存储–对于 AWS 中的本地存储和 EBS 存储,我们一次只需要一个容器就可以读写卷,这包含在ReadWriteOnce访问模式中。 spec.resources.requests.storage属性指定持久卷的大小,在本例中,我们将其配置为 8 GB。 If you are using Docker for Windows, you will be prompted to share your C:\ with Docker the first time you attempt to use the Docker hostPath provisioner.

如果您现在使用kubectl部署持久卷声明,您可以使用kubectl get pvc命令查看您新创建的声明:

> kubectl apply -f k8s/db/storage.yaml persistentvolumeclaim "todobackend-data" created > kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE todobackend-data Bound pvc-afba5984-9223-11e8-bc1c-025000000001 8Gi RWO hostpath 5s

您可以看到,当您创建持久卷声明时,会动态创建一个持久卷。使用 Docker Desktop 时,这实际上是在路径~/.docker/Volumes//中创建的:

> ls -l ~/.docker/Volumes/todobackend-data total 0 drwxr-xr-x 2 jmenga staff 64 28 Jul 17:04 pvc-afba5984-9223-11e8-bc1c-025000000001

如果您使用的是 Windows Docker,而您使用的是 Linux 的 Windows 子系统,您可以创建一个指向 Windows 主机上.docker文件夹的符号链接:

> ln -s /mnt/c/Users//.docker ~/.docker > ls -l ~/.docker/Volumes/todobackend-data total 0 drwxrwxrwx 1 jmenga jmenga 4096 Jul 29 17:04 pvc-c02a8614-932d-11e8-b8aa-00155d010401

请注意,如果您按照[第 1 章] 01.html

创建数据库服务

现在我们已经创建了一个持久的卷声明,我们可以定义数据库服务了。我们将在todobackend存储库中一个名为k8s/db/deployment.yaml的新文件中定义数据库服务,在这里我们创建一个服务和部署定义:

apiVersion: v1 kind: Service metadata: name: todobackend-db spec: selector: app: todobackend-db clusterIP: None ports: - protocol: TCP port: 3306 --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend-db labels: app: todobackend-db spec: selector: matchLabels: app: todobackend-db template: metadata: labels: app: todobackend-db spec: volumes: - name: data persistentVolumeClaim: claimName: todobackend-data containers: - name: db image: mysql:5.7 livenessProbe: exec: command: - /bin/sh - -c - "mysqlshow -h 127.0.0.1 -u $(MYSQL_USER) -p$(cat /tmp/secrets/MYSQL_PASSWORD)" volumeMounts: - name: data mountPath: /var/lib/mysql args: - --ignore-db-dir=lost+found env: - name: MYSQL_DATABASE value: todobackend - name: MYSQL_USER value: todo - name: MYSQL_ROOT_PASSWORD value: super-secret-password - name: MYSQL_PASSWORD value: super-secret-password

我们首先定义一个名为todobackend-db的服务,发布默认的 MySQL TCP 端口3306。请注意,我们指定了None的spec.clusterIP值,这将创建一个无头服务。无头服务对于单实例服务很有用,它允许 pod 的 IP 地址用作服务端点,而不是使用带有虚拟 IP 地址的 kube-proxy 组件,该组件只能对单个端点进行负载平衡。定义一个无头服务仍然会为该服务发布一个 DNS 记录,但是会将该记录与 pod IP 地址相关联,确保todo back 和应用可以通过名称连接到todobackend-db服务。然后,我们为todobackend-db服务创建一个部署,并定义一个名为data的卷,该卷映射到我们之前创建的持久卷声明,并装载到 MySQL 容器中的数据库数据目录(/var/lib/mysql)中。请注意,我们指定了args属性(相当于 Docker/Docker Compose 中的 CMD/command 指令),该属性配置 MySQL 忽略lost+found目录(如果存在的话)。虽然这在使用 Docker Desktop 时不会成为问题,但在 AWS 中会成为问题,原因与前面 Docker Swarm 一章中讨论的相同。最后,我们创建一个类型为exec的活动探测器,它执行mysqlshow命令来检查到 MySQL 数据库的连接是否可以在 MySQL 容器中本地建立。因为 MySQL 机密位于一个文件中,所以我们将 MySQL 命令包装在一个 shell 进程中(/bin/sh),这允许我们使用$(cat /tmp/secrets/MYSQL_PASSWORD)命令替换。 Kubernetes allows you resolve environment variables at execution time by using the syntax $(). For example, the $(MYSQL_USER) value included in the preceding liveness probe will be resolved to the environment variable MYSQL_USER when the probe is executed. See https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#use-environment-variables-to-define-arguments for more details.

如果您现在部署数据库服务和部署资源,您可以使用kubectl get svc和kubectl get endpoints命令来验证您的无头服务配置:

> kubectl apply -f k8s/db/deployment.yaml service "todobackend-db" created deployment.apps "todobackend-db" created > kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 8h todobackend LoadBalancer 10.103.210.17 localhost 80:31417/TCP 1d todobackend-db ClusterIP None 3306/TCP 6s > kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.65.3:6443 2d todobackend 10.1.0.44:8000,10.1.0.46:8000 1d todobackend-db 10.1.0.55:3306 14s

请注意,todobackend-db服务部署的集群 IP 为 none,这意味着服务的发布端点是todobackend-db pod 的 IP 地址。

您还可以通过在本地主机上的~/.docker/Volumes/todobackend-data中列出物理卷目录的内容来验证数据卷是否已正确创建:

> ls -l ~/.docker/Volumes/todobackend-data/pvc-afba5984-9223-11e8-bc1c-025000000001 total 387152 -rw-r----- 1 jmenga wheel 56 27 Jul 21:49 auto.cnf -rw------- 1 jmenga wheel 1675 27 Jul 21:49 ca-key.pem ... ... drwxr-x--- 3 jmenga wheel 96 27 Jul 21:49 todobackend

如果您现在只删除数据库服务和部署,您应该能够验证持久卷没有被删除并保持不变,这意味着您可以重新创建数据库服务并重新连接到data卷而不会丢失数据:

> kubectl delete -f k8s/db/deployment.yaml service "todobackend-db" deleted deployment.apps "todobackend-db" deleted > ls -l ~/.docker/Volumes/todobackend-data/pvc-afba5984-9223-11e8-bc1c-025000000001 total 387152 -rw-r----- 1 jmenga wheel 56 27 Jul 21:49 auto.cnf -rw------- 1 jmenga wheel 1675 27 Jul 21:49 ca-key.pem ... ... drwxr-x--- 3 jmenga wheel 96 27 Jul 21:49 todobackend > kubectl apply -f k8s/db/deployment.yaml service "todobackend-db" created deployment.apps "todobackend-db" created

前面的代码是一个很好的例子,说明了为什么我们将持久卷声明分离到自己的文件中——这样做意味着我们可以轻松管理数据库服务的生命周期,而不会丢失任何数据。如果您确实想要销毁数据库服务及其数据,您可以选择删除永久卷声明,在这种情况下,Docker Desktop hostPath 置备程序将自动删除永久卷和任何存储的数据。 Kubernetes also supports a controller called a StatefulSet, which is specifically designed for stateful applications such as databases. You can read more about StatefulSets at https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/.

创造和消费机密

Kubernetes 支持 secret 对象,该对象允许密码或令牌等敏感数据以加密格式安全存储,然后根据需要私下暴露给您的容器。Kubernetes 机密以键/值映射或字典格式存储,这与 Docker 机密不同,正如您在上一章中看到的,Docker 机密通常只存储机密值。

您可以使用文字值手动创建机密,或者将机密值包含在文件中并应用该文件。我建议使用文字值创建您的机密,以避免将您的机密存储在配置文件中,这些文件可能会被无意中提交并推送到您的源代码存储库:

> kubectl create secret generic todobackend-secret \ --from-literal=MYSQL_PASSWORD="$(openssl rand -base64 32)" \ --from-literal=MYSQL_ROOT_PASSWORD="$(openssl rand -base64 32)" \ --from-literal=SECRET_KEY="$(openssl rand -base64 50)" secret "todobackend-secret" created > kubectl describe secrets/todobackend-secret Name: todobackend-secret Namespace: default Labels: Annotations: Type: Opaque Data ==== MYSQL_PASSWORD: 44 bytes MYSQL_ROOT_PASSWORD: 44 bytes SECRET_KEY: 69 bytes

在前面的示例中,您使用kubectl create secret generic命令创建了一个名为todobackend-secret的机密,该机密存储了三个机密值。请注意,每个值都存储有一个与预期环境变量同名的键,这将使这些值的配置易于使用。

现在创建了机密,您可以配置todobackend和db部署来使用机密。Kubernetes 包含一种称为 secret 的特殊卷类型,允许您将机密安装在容器中的可配置位置,然后您的应用可以安全地私下读取这些机密。

为数据库服务使用机密

让我们首先更新在k8s/db/deployment.yaml文件中定义的数据库部署资源,以使用todobackend-secret:

apiVersion: v1 kind: Service metadata: name: todobackend-db spec: selector: app: todobackend-db clusterIP: None ports: - protocol: TCP port: 3306 --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend-db labels: app: todobackend-db spec: selector: matchLabels: app: todobackend-db template: metadata: labels: app: todobackend-db spec: volumes: - name: data persistentVolumeClaim: claimName: todobackend-data - name: secrets secret: secretName: todobackend-secret items: - key: MYSQL_PASSWORD path: MYSQL_PASSWORD - key: MYSQL_ROOT_PASSWORD path: MYSQL_ROOT_PASSWORD containers: - name: db image: mysql:5.7 livenessProbe: exec: command: - /bin/sh - -c - "mysqlshow -h 127.0.0.1 -u $(MYSQL_USER) -p$(cat /tmp/secrets/MYSQL_PASSWORD)" volumeMounts: - name: data mountPath: /var/lib/mysql - name: secrets mountPath: /tmp/secrets readOnly: true env: - name: MYSQL_DATABASE value: todobackend - name: MYSQL_USER value: todo - name: MYSQL_ROOT_PASSWORD_FILE value: /tmp/secrets/MYSQL_ROOT_PASSWORD - name: MYSQL_PASSWORD_FILE value: /tmp/secrets/MYSQL_PASSWORD

您首先创建一个名为secrets的卷,其类型为secret,引用了我们之前创建的todobackend-secret。默认情况下,所有机密项目都可用,但是您可以通过可选的items属性控制哪些项目发布到卷中。因为todobackend-secret包含了特定于 todobackend 应用的SECRET_KEY机密,所以我们配置items列表以排除该项目,并且只显示MYSQL_PASSWORD和MYSQL_ROOT_PASSWORD键。请注意,指定的path是必需的,并表示为基于机密卷在每个容器中的安装位置的相对路径。

然后将secrets卷以只读方式装载到db容器中的/tmp/secrets中,并更新与密码相关的环境变量以引用机密文件,而不是直接使用环境中的值。请注意,每个机密值都将在一个文件中创建,该文件是根据装载机密卷的文件夹中的密钥命名的。

要部署我们的新配置,您首先需要删除数据库服务及其关联的持久卷,因为这包括以前的凭据,然后重新部署数据库服务。当您执行删除和应用操作时,通过引用整个k8s/db目录,您可以非常容易地做到这一点,而不是单独指定每个文件:

> kubectl delete -f k8s/db service "todobackend-db" deleted deployment.apps "todobackend-db" deleted persistentvolumeclaim "todobackend-data" deleted > kubectl apply -f k8s/db service "todobackend-db" created deployment.apps "todobackend-db" created persistentvolumeclaim "todobackend-data" created

一旦您重新创建了db服务,您就可以使用kubectl exec命令来验证MYSQL_PASSWORD和MYSQL_ROOT_PASSWORD机密项目是否已写入/tmp/secrets:

> kubectl exec $(kubectl get pods -l app=todobackend-db -o=jsonpath='{.items[0].metadata.name}')\ ls /tmp/secrets MYSQL_PASSWORD MYSQL_ROOT_PASSWORD 为应用使用机密

我们现在需要通过修改k8s/app/deployment.yaml文件来更新 todobackend 服务以消耗我们的机密:

... ... --- apiVersion: apps/v1 kind: Deployment metadata: name: todobackend labels: app: todobackend spec: replicas: 2 selector: matchLabels: app: todobackend template: metadata: labels: app: todobackend spec: securityContext: fsGroup: 1000 volumes: - name: public emptyDir: - name: secrets secret: secretName: todobackend-secret items: - key: MYSQL_PASSWORD path: MYSQL_PASSWORD - key: SECRET_KEY path: SECRET_KEY initContainers: - name: collectstatic image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent volumeMounts: - name: public mountPath: /public command: ["python3","manage.py","collectstatic","--no-input"] env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release containers: - name: todobackend image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 8000 livenessProbe: httpGet: port: 8000 volumeMounts: - name: public mountPath: /public - name: secrets mountPath: /tmp/secrets readOnly: true command: - uwsgi - --http=0.0.0.0:8000 - --module=todobackend.wsgi - --master - --die-on-term - --processes=4 - --threads=2 - --check-static=/public env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release - name: SECRETS_ROOT value: /tmp/secrets - name: MYSQL_HOST value: todobackend-db - name: MYSQL_USER value: todo

您必须定义secrets体积,并确保只有MYSQL_PASSWORD和SECRET_KEY项目暴露在至容器中。在中以只读方式装载卷以装入应用容器后,必须使用secrets装载路径配置SECRETS_ROOT环境变量。回想一下,在上一章中,我们增加了对至应用消费 Docker 机密的支持,默认情况下,Docker 机密位于/run/secrets。然而,由于/run是一个特殊的 tmpfs 文件系统,您不能在这个位置使用常规文件系统挂载来挂载您的机密,因此我们需要配置SECRETS_ROOT环境变量,它重新配置应用将查看的机密位置。我们还必须配置MYSQL_HOST和MYSQL_USER环境变量,以便随着MYSQL_PASSWORD的机密一起,到应用具有连接到数据库服务所需的信息。

如果您现在部署更改,您应该能够验证正确的机密项目是否安装在至容器中:

> kubectl apply -f k8s/app/ service "todobackend" unchanged deployment.apps "todobackend" configured > kubectl get pods NAME READY STATUS RESTARTS AGE todobackend-74d47dd994-cpvl7 1/1 Running 0 35s todobackend-74d47dd994-s2pp8 1/1 Running 0 35s todobackend-db-574fb5746c-xcg9t 1/1 Running 0 12m > kubectl exec todobackend-74d47dd994-cpvl7 ls /tmp/secrets MYSQL_PASSWORD SECRET_KEY

如果您浏览到http://localhost/todos,您应该会收到一个错误,指示数据库表不存在,这意味着应用现在已经成功连接并验证到数据库,但是缺少应用所需的模式和表。

运行作业

我们的todo back and应用几乎完全正常运行,但是我们需要执行一个关键的部署任务,那就是运行数据库迁移,以确保在todo back and数据库中存在正确的模式和表。正如您在本书中所看到的,数据库迁移应该在每次部署中只执行一次,而不管我们的应用运行了多少个实例。Kubernetes 通过一个特殊类型的控制器作业来支持这种性质的任务,顾名思义,它运行一个任务或进程(以 pod 的形式),直到作业成功完成。

要为所需的数据库迁移任务创建作业,我们将在todobackend存储库中创建一个名为k8s/app/migrations.yaml的新文件,它允许您独立于位于同一位置的deployment.yaml文件中定义的其他应用资源运行作业:

apiVersion: batch/v1 kind: Job metadata: name: todobackend-migrate spec: backoffLimit: 4 template: spec: restartPolicy: Never volumes: - name: secrets secret: secretName: todobackend-secret items: - key: MYSQL_PASSWORD path: MYSQL_PASSWORD containers: - name: migrate image: 385605022855.dkr.ecr.us-east-1.amazonaws.com/docker-in-aws/todobackend imagePullPolicy: IfNotPresent volumeMounts: - name: secrets mountPath: /tmp/secrets readOnly: true command: ["python3","manage.py","migrate","--no-input"] env: - name: DJANGO_SETTINGS_MODULE value: todobackend.settings_release - name: SECRETS_ROOT value: /tmp/secrets - name: MYSQL_HOST value: todobackend-db - name: MYSQL_USER value: todo

您必须指定一种Job来将此资源配置为作业,并且在大多数情况下,该配置与我们之前创建的 pod/部署模板非常相似,除了spec.backoffLimit属性和模板spec.restartPolicy属性,前者定义了如果作业失败,Kubernetes 应尝试重新运行作业的次数,后者应始终设置为Never用于作业。

如果现在运行作业,您应该验证数据库迁移是否成功运行:

> kubectl apply -f k8s/app service "todobackend" unchanged deployment.apps "todobackend" unchanged job.batch "todobackend-migrate" created > kubectl get jobs NAME DESIRED SUCCESSFUL AGE todobackend-migrate 1 1 6s > kubectl logs jobs/todobackend-migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, todo Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK Applying todo.0001_initial... OK

此时,您已经成功地将 todo back and 应用部署到了完全正常的状态,您应该能够连接到 todo back and 应用并创建、更新和删除 todo 项。

创建 EKS 集群

现在,您已经对 Kubernetes 有了坚实的了解,并且已经定义了在本地部署和运行 todobackend 应用所需的核心资源,现在是时候将我们的注意力转移到弹性 Kubernetes 服务(EKS)上了。 EKS 支持的核心资源是 EKS 集群,它代表了一个完全管理的、高可用性的 Kubernetes 管理器集群,为您管理 Kubernetes 控制平面。在本节中,我们将重点关注在 AWS 中创建 EKS 集群,建立对集群的认证和访问,以及部署 Kubernetes 仪表板。

创建 EKS 集群包括以下主要任务:

安装客户端组件:为了管理您的 EKS 集群,您需要安装各种客户端组件,包括kubectl(您已经安装了)和用于 Kubernetes 工具的 AWS IAM 认证器。 创建集群资源:这建立了 Kubernetes 的控制平面组件,由 Kubernetes 主节点组成。使用 EKS 时,主机作为完全托管的服务提供。 为 EKS 配置 kubectl:这允许您使用本地 kube CTL 客户端管理 EKS。 创建工作节点:这由 Kubernetes 节点组成,旨在运行您的容器工作负载。使用 EKS 时,您负责创建自己的工作节点,通常以 EC2 自动扩展组的形式部署。就像对于 ECS 服务一样,AWS 提供了一个 eks 优化的 AMI(https://docs . AWS . Amazon . com/eks/latest/user guide/eks-optimized-AMI . html),其中包括工作节点加入 EKS 集群所需的所有软件组件。 部署 Kubernetes 仪表板:Kubernetes 仪表板为您提供了基于 web 的管理界面,用于管理和监控您的集群和容器应用。 At the time of writing, EKS clusters are not part of the AWS free tier and cost $0.20 USD per minute to run, so bear this in mind before you continue (see https://aws.amazon.com/eks/pricing/ for latest pricing information). We will be using CloudFormation templates to deploy both the EKS cluster and EKS worker nodes, so you can easily tear down and recreate your EKS cluster and worker nodes as required to reduce costs. 安装客户端组件

要管理您的 EKS 集群,您必须安装kubectl以及用于 Kubernetes 组件的 AWS IAM 认证器,该认证器允许kubectl使用您的 IAM 凭证向您的 EKS 集群进行认证。

您已经安装了kubectl,所以要为 Kubernetes 安装 AWS IAM 认证器,您需要安装一个名为aws-iam-authenticator的二进制文件,该文件由 AWS 发布,如下所示:

> curl -fs -o /usr/local/bin/aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/darwin/amd64/aws-iam-authenticator > chmod +x /usr/local/bin/aws-iam-authenticator 创建群集资源

在创建 EKS 群集之前,您需要确保您的 AWS 帐户满足以下先决条件:

VPC 资源 : EKS 资源必须部署到一个至少有三个子网的 VPC。AWS 建议您为每个 EKS 群集创建自己的专用 VPC 和子网,但是在本章中,我们将使用在您的 AWS 帐户中自动创建的默认 VPC 和子网。请注意,当您创建 VPC 并定义集群将使用的子网时,您必须指定所有子网,您期望您的工作节点和负载平衡器将部署在这些子网中。推荐的模式是在私有子网中部署工作节点,并确保您也包括公共子网,以便 EKS 可以根据需要创建面向公共的负载平衡器。 EKS 服务角色:创建 EKS 集群时,您必须指定一个 IAM 角色来授予对 EKS 服务的访问权限,以管理您的集群。 控制平面安全组:您必须提供一个安全组,用于 EKS 集群管理器和工作节点之间的控制平面通信。EKS 服务将修改安全组规则,因此您应该为此要求创建一个新的空安全组。 aws 文档包括一个入门部分,其中提供了如何使用 AWS 控制台创建 eks 集群的详细信息。考虑到 cloud information 和我们在本书中使用的基础架构即代码方法支持 EKS,我们需要在todobackend-aws存储库中创建一个名为eks的文件夹,并在名为todobackend-aws/eks/stack.yml的新 cloud information 模板文件中定义我们的 EKS 集群和相关的 EKS 服务角色:AWSTemplateFormatVersion: "2010-09-09" Description: EKS Cluster Parameters: Subnets: Type: List Description: Target subnets for EKS cluster VpcId: Type: AWS::EC2::VPC::Id Description: Target VPC Resources: EksServiceRole: Type: AWS::IAM::Role Properties: RoleName: eks-service-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - eks.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy - arn:aws:iam::aws:policy/AmazonEKSServicePolicy EksClusterSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: eks-cluster-control-plane-sg GroupDescription: EKS Cluster Control Plane Security Group VpcId: !Ref VpcId Tags: - Key: Name Value: eks-cluster-sg EksCluster: Type: AWS::EKS::Cluster Properties: Name: eks-cluster RoleArn: !Sub $ ResourcesVpcConfig: SubnetIds: !Ref Subnets SecurityGroupIds: - !Ref EksClusterSecurityGroup

该模板需要两个输入参数——目标 VPC 标识和目标子网标识。EksServiceRole资源创建一个 IAM 角色,该角色授予eks.awsamazon.com服务代表您管理 EKS 集群的能力,如ManagedPolicyArns属性中引用的托管策略所指定的。然后,您必须为控制平面通信定义一个空的安全组,最后定义 EKS 集群资源,引用RoleArn属性的EksServiceRole资源,并定义一个以输入ApplicationSubnets为目标并使用EksClusterSecurityGroup资源的 VPC 配置。

现在,您可以使用aws cloudformation deploy命令部署该模板,如下所示:

> export AWS_PROFILE=docker-in-aws > aws cloudformation deploy --template-file stack.yml --stack-name eks-cluster \ --parameter-overrides VpcId=vpc-f8233a80 Subnets=subnet-a5d3ecee,subnet-324e246f,subnet-d281a2b6\ --capabilities CAPABILITY_NAMED_IAM Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - eks-cluster

创建群集大约需要 10 分钟,创建后,您可以使用 AWS CLI 获得有关群集的更多信息:

> aws eks describe-cluster --name eks-cluster --query cluster.status "ACTIVE" > aws eks describe-cluster --name eks-cluster --query cluster.endpoint "https://E7B5C85713AD5B11625D7A689F99383F.sk1.us-east-1.eks.amazonaws.com" > aws eks describe-cluster --name eks-cluster --query cluster.certificateAuthority.data "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EY3lNakV3TURRME9Gb1hEVEk0TURjeE9URXdNRFEwT0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUEh5CkVsajhLMUQ4M1V3RDFmdlhqYi9TdGZBK0tvWEtZNkVtZEhudnNXeWh1Snd2aGhkZDU2M0tVdGJnYW15Z0pxMVIKQkNCTWptWXVocG8rWm0ySEJrckZGakFFZDVIN1lWUXVOSm15TXdrQVV5MnpFTUU5SjJid3hkVEpqZ3pZdmlwVgpJc05zd3pIL1lSa1NVSElDK0VSaCtURmZJODhsTTBiZlM1R1pueUx0VkZCS3RjNGxBREVxRE1BTkFoaEc5OVZ3Cm5hL2w5THU2aW1jT1VOVGVCRFB0L1hxNGF3TFNUOEgwQlVvWGFwbEt0cFkvOFdqR055RUhzUHZHdXNXU3lkTHMKK3lKNXBlUm8yR3Nxc0VqMGhsbHpuV0RXWnlqQVU5Ni82QXVKRGZVSTBING1WNkpCZWxVU0tTRTZBOU1GSjRjYgpHeVpkYmh0akg1d3Zzdit1akNjQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIRkRIODZnNkNoR2FMejBQb21EK2tyc040SUMKRzhOb0xSc2xkTkJjQmlRczFYK0hKenNxTS9TN0svL1RhUndqVjRZTE1hbnBqWGp4TzRKUWh4Q0ZHR1F2SHptUApST1FhQXRjdWRJUHYySlg5eUlOQW1rT0hDaloyNm1Yazk1b2pjekxQRE1NTlFVR2VmbXUxK282T1ZRUldTKzBMClpta211KzVyQVVFMWtTK00yMDFPeFNGcUNnL0VDd0F4ZXd5YnFMNGw4elpPWCs3VzlyM1duMWh6a3NhSnIrRHkKUVRyQ1p2MWJ0ZENpSnhmbFVxWXN5UEs1UDh4NmhKOGN2RmRFUklFdmtYQm1VbjRkWFBWWU9IdUkwdElnU2h1RAp3K0IxVkVOeUF3ZXpMWWxLaGRQQTV4R1BMN2I0ZmN4UXhCS0VlVHpaUnUxQUhMM1R4THIxcVdWbURUbz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="

本章后面的内容都需要群集端点和证书颁发机构数据,因此请注意这些值。

为 EKS 配置 kubectl

创建 EKS 集群后,现在需要将新集群添加到本地kubectl配置中。默认情况下,kubectl知道的所有集群都被定义在一个名为~/.kube/config的文件中,如果你使用的是 Mac 的 Docker 或 Windows 的 Docker,这个文件目前将包含一个名为docker-for-desktop-cluster的集群。

以下代码演示了如何将您的 EKS 集群和相关配置添加到~/.kube/config文件中:

apiVersion: v1 clusters: - cluster: insecure-skip-tls-verify: true server: https://localhost:6443 name: docker-for-desktop-cluster - cluster: certificate-authority-data: server: https://E7B5C85713AD5B11625D7A689F99383F.sk1.us-east-1.eks.amazonaws.com name: eks-cluster contexts: - context: cluster: docker-for-desktop-cluster user: docker-for-desktop name: docker-for-desktop - context: cluster: eks-cluster user: aws name: eks current-context: docker-for-desktop-cluster kind: Config preferences: users: - name: aws user: exec: apiVersion: client.authentication.k8s.io/v1alpha1 args: - token - -i - eks-cluster command: aws-iam-authenticator env: - name: AWS_PROFILE value: docker-in-aws - name: docker-for-desktop user: client-certificate-data: ... client-key-data: ...

您必须首先向clusters属性添加一个名为eks-cluster的新集群,指定您之前在创建 EKS 集群后捕获的证书颁发机构数据和服务器端点。然后,您必须添加名为eks的上下文,这将允许您在本地 Kubernetes 服务器和您的 EKS 集群之间进行切换,最后,向用户部分添加名为aws的新用户,该用户部分由eks上下文用来向您的 EKS 集群进行认证。aws用户配置将 kubectl 配置为执行您之前安装的aws-iam-authenticator组件,传递参数token -i eks-cluster并使用您的本地docker-in-aws配置文件来验证访问。执行此命令将自动向kubectl返回一个认证令牌,该令牌可用于向您的 EKS 集群进行认证。

有了前面的配置,您现在应该能够访问名为eks的新上下文,并验证与 EKS 群集的连接,如下所示:

> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * docker-for-desktop docker-for-desktop-cluster docker-for-desktop eks eks-cluster aws > kubectl config use-context eks Switched to context "eks". > kubectl get all Assume Role MFA token code: ****** NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.100.0.1 443/TCP 1h

请注意,如果您正在使用我们在前面章节中设置的多因素认证 ( MFA )配置,每次您对您的 EKS 集群运行kubectl命令时,都会提示您输入一个 MFA 令牌,这将很快变得令人厌烦。

要暂时禁用多功能事务机,您可以使用aws iam remove-user-from-group命令从用户组中删除您的用户帐户:

## Removes user from Users group, removing MFA requirement ## To restore MFA run: aws iam add-user-to-group --user-name justin.menga --group-name Users > aws iam remove-user-from-group --user-name justin.menga --group-name Users

然后在~/.aws/config文件中为您的本地 AWS 配置文件注释mfa_serial行:

[profile docker-in-aws] source_profile = docker-in-aws role_arn = arn:aws:iam::385605022855:role/admin role_session_name=justin.menga region = us-east-1 ## mfa_serial = arn:aws:iam::385605022855:mfa/justin.menga 创建工作节点

设置 EKS 的下一步是创建将加入您的 EKS 集群的工作节点。与完全由 AWS 管理的 Kubernetes 主节点不同,您负责创建和管理您的工作节点。AWS 提供了一个 EKS 优化的 AMI,包括加入 EKS 集群和作为 EKS 工人操作所需的所有软件。您可以浏览https://docs . AWS . Amazon . com/eks/latest/user guide/eks-optimized-AMI . html获取您所在地区的最新 AMI ID:

Amazon EKS-Optimized AMI

在撰写本书时,EKS 优化的 AMI 需要使用我们在前面章节中了解到的 cfn-init 框架进行大量配置。创建工作节点的推荐方法是使用由 AWS 发布的预定义 CloudFormation 模板,该模板已经包含了在https://docs . AWS . Amazon . com/eks/latest/user guide/launch-workers . html中指定的所需配置:

Worker CloudFormation template URL

现在,您可以通过在 AWS 控制台中选择服务 | 云信息,单击创建栈按钮,并粘贴您之前在选择模板部分中获得的工作者模板 URL,为您的工作者节点创建一个新的云信息栈:

Creating a worker node CloudFormation stack

点击下一步后,系统会提示您输入栈名称(您可以指定一个eks-cluster-workers或类似的名称),并提供以下参数:

集群名称:指定您的 EKS 集群的名称(在我们的示例中为eks-cluster)。 集群控制平面安全组:控制平面安全组的名称。在我们的示例中,我们之前在创建 EKS 集群时创建了一个名为eks-cluster-control-plane-sg的安全组。 节点组名:这定义了将为您的员工创建的 EC2 自动缩放组的部分名称。对于我们的场景,您可以指定一个eks-cluster-workers或类似的名称。 节点自动缩放组大小 和 节点自动缩放组大小:默认分别设置为 1 和 3。请注意,云信息模板将自动缩放组的所需大小设置为NodeAutoScalingGroupMaxSize参数的值,因此您可能需要降低该值。 节点实例类型:您可以使用预定义的工作人员云信息模板指定的最小实例类型是t2.small。对于 EKS 来说,节点实例类型不仅在 CPU 和内存资源方面很重要,而且在网络需求方面对 pod 容量也有影响。eks 网络模型(https://docs . AWS . Amazon . com/eks/latest/user guide/pod-networking . html)使用弹性网络接口(ENI)和运行在每个 ENI 上的辅助 IP 地址的组合,将 EKS 集群中的每个 pod 公开为在你的 VPC 内可到达的 IP 地址。您可以参考https://docs . AWS . Amazon . com/AWSEC2/latest/user guide/using-Eni . html # available pereni,它描述了各种 EC2 实例类型的每个接口的最大 eni 和辅助 IP 地址数量,并最终确定了每个节点可以运行的最大 pods 数量。 节点映像标识:指定您所在地区的 EKS 优化急性心肌梗死的标识(参见之前的截图)。 KeyName :指定您的帐户中现有的 EC2 密钥对(例如,您在本书前面创建的 admin 密钥对)。 VpcId :指定您的 EKS 集群所在的 VpcId。 子网:指定您想要放置员工的子网。

配置好所需的各种参数后,单击下一步按钮两次,最后确认云信息可以创建 IAM 资源,然后单击创建按钮部署您的工作节点。成功创建栈后,打开栈的输出选项卡,记下NodeInstanceRole输出,这是下一个配置步骤所需的:

Obtaining the NodeInstanceRole output

将工作节点加入您的 EKS 集群

成功部署云信息栈后,您的工作节点将尝试加入您的集群,但是在他们加入之前,您需要通过将名为aws-auth的 AWS 认证器ConfigMap资源应用于您的集群来授予对工作节点的 EC2 实例角色的访问权限。 A ConfigMap is simply a key/value data structure used to store configuration data that can be used by different resources in your cluster. The aws-auth ConfigMap is used by EKS to grant AWS users the ability to interact with your cluster, which you can read more about at https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html. You can also download a sample aws-auth ConfigMap from https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/aws-auth-cm.yaml.

要创建aws-auth配置图,在todobackend-aws/eks文件夹中创建一个名为aws-auth-cm.yaml的文件:

apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - rolearn: arn:aws:iam::847222289464:role/eks-cluster-workers-NodeInstanceRole-RYP3UYR8QBYA username: system:node: groups: - system:bootstrappers - system:nodes

在前面的示例中,您需要粘贴在创建 workers CloudFormation 栈时获得的NodeInstanceRole输出的值。创建此文件后,您现在可以使用kubectl apply命令将其应用到您的 EKS 集群,然后通过运行kubectl get nodes --watch等待您的工作节点加入集群:

> kubectl apply -f aws-auth-cm.yaml configmap "aws-auth" created > kubectl get nodes --watch NAME STATUS ROLES AGE VERSION ip-172-31-15-111.us-west-2.compute.internal NotReady 20s v1.10.3 ip-172-31-28-179.us-west-2.compute.internal NotReady 16s v1.10.3 ip-172-31-38-41.us-west-2.compute.internal NotReady 13s v1.10.3 ip-172-31-15-111.us-west-2.compute.internal NotReady 23s v1.10.3 ip-172-31-28-179.us-west-2.compute.internal NotReady 22s v1.10.3 ip-172-31-38-41.us-west-2.compute.internal NotReady 22s v1.10.3 ip-172-31-15-111.us-west-2.compute.internal Ready 33s v1.10.3 ip-172-31-28-179.us-west-2.compute.internal Ready 32s v1.10.3 ip-172-31-38-41.us-west-2.compute.internal Ready 32s v1.10.3

一旦您的所有工作人员的状态为Ready,您就已经成功地将您的工作人员节点加入到您的 EKS 集群中。

部署 Kubernetes 仪表板

设置 EKS 集群的最后一步是将 Kubernetes 仪表板部署到集群中。Kubernetes 仪表板是一个强大而全面的基于网络的管理界面,用于管理和监控您的集群和容器应用,并作为基于容器的应用部署在 Kubernetes 集群的kube-system命名空间内。仪表板由许多组件组成,我在此不再赘述,但您可以在https://github.com/kubernetes/dashboard了解更多关于仪表板的信息。

为了部署仪表板,我们将首先创建一个名为todobackend-aws/eks/dashboard的文件夹,并继续下载和应用组成仪表板的各种组件到该文件夹:

> curl -fs -O https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml > curl -fs -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/heapster.yaml > curl -fs -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/influxdb.yaml > curl -fs -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml > kubectl apply -f kubernetes-dashboard.yaml secret "kubernetes-dashboard-certs" created serviceaccount "kubernetes-dashboard" created role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created deployment.apps "kubernetes-dashboard" created service "kubernetes-dashboard" created > kubectl apply -f heapster.yaml serviceaccount "heapster" createddeployment.extensions "heapster" createdservice "heapster" created > kubectl apply -f influxdb.yaml deployment.extensions "monitoring-influxdb" created service "monitoring-influxdb" created > kubectl apply -f heapster-rbac.yaml clusterrolebinding.rbac.authorization.k8s.io "heapster" created

然后,您需要创建一个名为eks-admin.yaml的文件,该文件创建具有完全集群管理员权限的服务帐户和集群角色绑定:

apiVersion: v1 kind: ServiceAccount metadata: name: eks-admin namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: eks-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: eks-admin namespace: kube-system

创建此文件后,您需要将其应用于您的 EKS 集群:

> kubectl apply -f eks-admin.yaml serviceaccount "eks-admin" created clusterrolebinding.rbac.authorization.k8s.io "eks-admin" created

有了eks-admin服务帐户,您可以通过运行以下命令来检索该帐户的认证令牌:

> kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}') Name: eks-admin-token-24kh4 Namespace: kube-system Labels: Annotations: kubernetes.io/service-account.name=eks-admin kubernetes.io/service-account.uid=6d8ba3f6-8dba-11e8-b132-02b2aa7ab028 Type: kubernetes.io/service-account-token Data ==== namespace: 11 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJla3MtYWRtaW4tdG9rZW4tMjRraDQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZWtzLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNmQ4YmEzZjYtOGRiYS0xMWU4LWIxMzItMDJiMmFhN2FiMDI4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmVrcy1hZG1pbiJ9.h7hchmhGUZKjdnZRk4U1RZVS7P1tvp3TAyo10TnYI_3AOhA75gC6BlQz4yZSC72fq2rqvKzUvBqosqKmJcEKI_d6Wb8UTfFKZPFiC_USlDpnEp2e8Q9jJYHPKPYEIl9dkyd1Po6er5k6hAzY1O1Dx0RFdfTaxUhfb3zfvEN-X56M34B_Gn3FPWHIVYEwHCGcSXVhplVMMXvjfpQ-0b_1La8fb31JcnD48UolkJ1Z_DH3zsVjIR9BfcuPRoooHYQb4blgAJ4XtQYQans07bKD9lmfnQvNpaCdXV_lGOx_I5vEbc8CQKTBdJkCXaWEiwahsfwQrYtfoBlIdO5IvzZ5mg ca.crt: 1025 bytes

前面示例中的关键信息是令牌值,当您连接到仪表板时,需要复制并粘贴令牌值。要连接到仪表板,您需要启动 kubectl 代理,该代理提供对 Kubernetes API 的 HTTP 访问:

> kubectl proxy Starting to serve on 127.0.0.1:8001

如果您现在浏览至http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/,系统将提示您登录仪表板,您需要在其中粘贴之前为eks-admin服务帐户检索到的令牌:

Signing in to the Kubernetes dashboard

登录后,如果您将命名空间更改为 kube-system 并选择工作负载 | 部署,您可能会看到一个错误,指示无法找到监控-influxdb 部署的映像:

Kubernetes dashboard deployment failure

如果是这种情况,您需要更新之前下载的todobackend-aws/eks/dashboard/influxdb.yml文件以引用k8s.gcr.io/heapster-influxdb-amd64:v1.3.3(这是一个已知问题(https://github.com/kubernetes/heapster/issues/2059)),在您阅读本章时可能存在也可能不存在):

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: monitoring-influxdb namespace: kube-system spec: replicas: 1 template: metadata: labels: task: monitoring k8s-app: influxdb spec: containers: - name: influxdb image: k8s.gcr.io/heapster-influxdb-amd64:v1.3.3 ... ...

如果您现在通过运行kubectl apply -f influxdb.yml重新应用文件,仪表板现在应该显示所有服务按预期运行。

将示例应用部署到 EKS

现在,我们的 EKS 集群和工作节点已经就位,并且我们已经确认可以部署到该集群,现在是时候将 todobackend 应用部署到 EKS 了。当您在 Kubernetes 中定义在本地运行应用所需的各种资源时,您已经完成了大部分艰苦的工作,所需要做的就是调整一些外部资源,例如负载平衡器和数据库服务的持久卷,以使用 AWS 本机服务。

现在,您需要执行以下配置任务:

使用 AWS 弹性块存储(EBS)配置对持久卷的支持 配置对 AWS 弹性负载平衡器的支持 部署示例应用 使用 AWS EBS 配置对持久卷的支持

在本章的前面,我们讨论了持久卷声明和存储类的概念,它们允许您从应用中抽象出存储基础架构的细节。我们了解到,在使用 Docker Desktop 时,提供了一个默认存储类,该类将自动创建 hostPath 类型的持久卷,这些卷可在~/.docker/Volumes从您的本地操作系统访问,这使得在将 Docker Desktop 与 Kubernetes 一起使用时,可以轻松调配、管理和维护持久卷。

使用 EKS 时,需要了解的是,与 Docker Desktop 不同,默认情况下,不会为您创建任何存储类。如果要支持持久卷声明,这要求您至少创建一个存储类,在大多数使用情况下,您通常会定义一个默认存储类,为集群提供标准的默认存储介质和卷类型。当使用 EKS 时,这些存储类的一个很好的候选是弹性块存储(EBS),它提供了一个标准的集成机制来支持在集群中作为工作节点运行的 EC2 实例的基于块的卷存储。Kubernetes 支持名为AWSElasticBlockStore的卷类型,允许您从工作节点访问和装载 EBS 卷,还支持名为aws-ebs的存储资源调配程序,该程序提供 EBS 卷的动态资源调配和管理。

通过开箱即用的对 AWS EBS 的本机支持,创建一个将自动调配 EBS 存储的默认存储类非常容易,我们将在名为todobackend-aws/eks/gp2-storage-class.yaml的文件中定义该存储类:

kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gp2 provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Delete mountOptions: - debug

我们将创建一个名为gp2的存储类,顾名思义,它将使用kubernetes.io/aws-ebs存储资源调配器从 AWS 调配类型为gp2或固态硬盘的 EBS 存储。parameters部分控制该存储选择,根据存储类型,可能有其他可用的配置选项,您可以在https://kubernetes . io/docs/concepts/storage-class/# AWS上了解更多。reclaimPolicy的值可以是Retain或Delete,它控制每当从 Kubernetes 中删除与存储类相关联的持久卷声明时,存储资源调配者是否应该保留或删除相关联的 EBS 卷。对于生产用例,您通常会将其设置为Retain,但是对于非生产环境,您可能希望将其设置为Delete的默认回收策略,以避免您不得不手动清理不再被您的集群使用的 EBS 卷。

现在,让我们在 EKS 集群中创建这个存储类,然后我们可以将新的存储类配置为集群的默认存储类:

> kubectl get sc No resources found. > kubectl apply -f eks/gp2-storage-class.yaml storageclass.storage.k8s.io "gp2" created > kubectl patch storageclass gp2 \ -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' storageclass.storage.k8s.io "gp2" patched > kubectl describe sc/gp2 Name: gp2 IsDefaultClass: Yes Annotations: ... Provisioner: kubernetes.io/aws-ebs Parameters: type=gp2 AllowVolumeExpansion: MountOptions: debug ReclaimPolicy: Delete VolumeBindingMode: Immediate Events:

创建存储类后,使用kubectl patch命令向存储类添加注释,将该类配置为默认类。可以看到,当运行kubectl describe sc/gp2命令查看存储类的详细信息时,IsDefaultClass属性被设置为Yes,确认新创建的类是集群的默认存储类。

有了这一点,到多包应用的 Kubernetes 配置现在有了一个默认存储类,可以应用于todobackend-data持久卷声明,该声明将基于存储类参数提供类型为gp2的 EBS 卷。 The eksServiceRole IAM role that you created earlier in this chapter includes the AmazonEKSClusterPolicy managed policy, which grants your EKS cluster the ability to manage EBS volumes. If you choose to implement your own custom IAM policies for the EKS service role, you must ensure that you include the various EC2 IAM permissions for managing volumes, such as ec2:AttachVolume, ec2:DetachVolume, ec2:CreateVolumes, ec2:DeleteVolumes, ec2:DescribeVolumes, and ec2:ModifyVolumes (this is not an exhaustive list). See https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html for details on the full list of IAM permissions that are granted by AWS-defined EKS service roles and managed policies.

配置对 AWS 弹性负载平衡器的支持

在本章的前面,当您为 todo back and 应用定义 Kubernetes 配置时,您为 todo back and 应用创建了一个类型为LoadBalancer的服务。我们讨论了负载平衡器的实现细节是特定于您的 Kubernetes 集群部署到的平台的,在 Docker Desktop 的情况下,Docker 提供了他们自己的负载平衡器组件,该组件允许服务暴露给您的开发机器上的本地网络接口。

使用 EKS 时,好消息是您不需要做任何事情来支持类型为LoadBalancer的服务–您的 EKS 集群将自动创建一个 AWS 弹性负载平衡器并将其与每个服务端点相关联,其中AmazonEKSClusterPolicy托管策略为此授予所需的 IAM 权限。 Kubernetes 确实允许您通过配置注释来配置LoadBalancer类型的特定于供应商的功能,这是一个元数据属性,给定的供应商在其目标平台上可以理解该属性,如果在不同的平台上部署,例如您的本地 Docker Desktop 环境,则可以忽略该属性。您可以在https://kubernetes . io/docs/concepts/services-networking/service/# publishing-services-service-type上阅读关于这些注释的更多信息,下面的示例演示了如何将特定于 AWS 弹性负载平衡器的几个注释添加到todobackend/k8s/app/deployment.yaml文件中的服务定义中:

apiVersion: v1 kind: Service metadata: name: todobackend annotations: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60" spec: selector: app: todobackend ports: - protocol: TCP port: 80 targetPort: 8000 type: LoadBalancer --- ... ...

在前面的示例中,我们添加了以下注释:

service.beta.kubernetes.io/aws-load-balancer-backend-protocol:这配置后端协议。值http确保在传入请求上设置X-Forward-For头,以便您的网络应用可以跟踪客户端的 IP 地址。 service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled:这将启用连接排放。 service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout:指定连接清空超时。

需要注意的一点是,注释期望每个值都是一个字符串值,因此请确保引用布尔值,如"true"和"false",以及任何数值,如"60",如前面的代码所示。

部署示例应用

现在,您已经准备好将示例应用部署到 AWS,您可以通过首先切换到 todobackend 存储库并确保使用您在本章前面创建的eks上下文来完成:

todobackend> kubectl config use-context eks Switched to context "eks". todobackend> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-for-desktop docker-for-desktop-cluster docker-for-desktop * eks eks-cluster aws 创造机密

回想一下,应用和数据库服务都依赖于我们在本地 Docker Desktop 上下文中手动创建的机密,因此您首先需要在您的 EKS 上下文中创建这些机密:

> kubectl create secret generic todobackend-secret \ --from-literal=MYSQL_PASSWORD="$(openssl rand -base64 32)" \ --from-literal=MYSQL_ROOT_PASSWORD="$(openssl rand -base64 32)" \ --from-literal=SECRET_KEY="$(openssl rand -base64 50)" secret "todobackend-secret" created 部署数据库服务

现在,您可以部署数据库服务,该服务将根据您之前创建的默认存储类的配置,创建一个由 EBS 支持的新持久卷:

> kubectl apply -f k8s/db service "todobackend-db" created deployment.apps "todobackend-db" created persistentvolumeclaim "todobackend-data" created > kubectl get pv NAME CAPACITY STATUS CLAIM STORAGECLASS pvc-18ac5d3f-925c-11e8-89e1-06186d140068 8Gi Bound default/todobackend-data gp2

您可以看到创建了一个持久卷,如果您浏览到 AWS 控制台中的服务 | EC2 ,并从左侧的弹性块存储菜单中选择卷,您应该可以看到持久值对应的 EBS 卷:

查看 EBS 卷

请注意,Kubernetes 用许多标记来标记 EBS 卷,这些标记允许容易地识别哪个持久卷和持久卷声明与它相关联的给定 EBS 卷。

在 Kubernetes 仪表板中,您可以通过选择工作负载 | 部署:来验证todobackend-db部署正在运行

查看 EBS 卷

部署应用服务

数据库服务就绪后,您现在可以继续部署应用:

> kubectl apply -f k8s/app service "todobackend" created deployment.apps "todobackend" created job.batch "todobackend-migrate" created

部署应用将执行以下任务:

创建运行数据库迁移的todobackend-migrate作业 创建todobackend部署,它运行一个 collectstatic initContainer,然后运行主 todobackend 应用容器 创建todobackend服务,该服务将部署带有 AWS ELB 前端的新服务

在 Kubernetes 仪表板中,如果您选择发现和负载平衡 | 服务并选择到后台处理服务,您可以查看该服务的每个内部端点,以及外部负载平衡器端点:

Viewing the todobackend service in the Kubernetes dashboard You can also obtain the external endpoint URL by running the kubectl describe svc/todobackend command.

如果单击外部端点 URL,您应该能够验证 todobackend 应用是否完全正常工作,所有静态内容是否正确显示,以及是否能够添加、删除和更新应用数据库中的 Todo 项目:

Verifying the todobackend application

分解示例应用

分解示例应用非常简单,如下所示:

> kubectl delete -f k8s/app service "todobackend" deleted deployment.apps "todobackend" deleted job.batch "todobackend-migrate" deleted > kubectl delete -f k8s/db service "todobackend-db" deleted deployment.apps "todobackend-db" deleted persistentvolumeclaim "todobackend-data" deleted

完成此操作后,您应该能够验证与 todo back and 服务关联的弹性负载平衡器资源以及 todo back and 数据库的 EBS 卷是否已被删除,前提是您已将默认存储类的回收策略配置为“删除”。当然,您还应该删除您在本章前面创建的工作节点栈和 EKS 集群栈,以避免不必要的费用。

摘要

在本章中,您学习了如何使用 Kubernetes 和 AWS 弹性 Kubernetes 服务(EKS)部署 Docker 应用。Kubernetes 已经凭借强大的开源社区成为领先的容器管理平台之一,随着 AWS 现在用 EKS 服务支持 Kubernetes 客户,Kubernetes 肯定会变得更加受欢迎。

您首先学习了如何在 Docker Desktop 中利用对 Kubernetes 的本机支持,这使得在本地启动和运行 Kubernetes 变得非常容易。您学习了如何创建各种核心 Kubernetes 资源,包括 pods、部署、服务、机密和作业,这些资源为在 Kubernetes 中运行应用提供了基本的构建块。您还学习了如何配置对持久存储的支持,利用持久卷声明将应用的存储需求从底层存储引擎中抽象出来。

然后向您介绍了 EKS,并学习了如何创建 EKS 集群和相关的支持资源,包括运行您的工作节点的 EC2 自动扩展组。您建立了对 EKS 集群的访问,并通过部署 Kubernetes 仪表板来测试集群是否正常工作,该仪表板为您的集群提供了丰富而强大的管理用户界面。

最后,您继续将 todobackend 应用部署到 EKS,其中包括与用于外部连接的 AWS 弹性负载平衡器(ELB)服务和用于提供持久存储的弹性块存储(EBS)的集成。这里的一个重要考虑是,除了添加一些注释来控制 todobackend 服务负载平衡器的配置之外,我们不需要修改之前在本地部署到 Docker Desktop 环境时创建的 Kubernetes 配置(这些注释在使用 Docker Desktop 时被忽略,因此被认为是“安全的”特定于供应商的配置元素)。您应该始终努力实现这一目标,因为它确保您的应用在不同的 Kubernetes 环境中具有最大的可移植性,并且可以独立于底层的 Kubernetes 平台轻松部署,无论是本地开发环境、AWS EKS 还是谷歌 Kubernetes 引擎(GKE)。

好吧,所有美好的事情都必须结束,现在是我说恭喜和感谢你完成这本书的时候了!很高兴写这本书,我希望你已经学会了如何利用 Docker 和 AWS 的力量来测试、构建、部署和操作你自己的容器应用。

问题 对/错:Kubernetes 是 Docker 桌面 CE 的一个原生特性。 您可以使用 commands 属性定义一个自定义命令字符串在 pod 定义中运行,并注意到 entrypoint 脚本容器不再执行。你如何解决这个问题? 对/错:Kubernetes 包括三种节点类型——管理器、工作器和代理。 对/错:Kubernetes 提供了与 AWS 应用负载平衡器的集成。 对/错:Kubernetes 支持将 EBS 卷重新定位到集群中的其他节点。 您可以使用什么组件向 web 应用公开 Kubernetes API? 对/错:Kubernetes 支持与弹性容器注册表的集成。 什么 Kubernetes 资源提供了可用于连接给定应用的多个实例的虚拟 IP 地址? 什么 Kubernetes 资源适合运行数据库迁移? 对/错:EKS 同时管理 Kubernetes 管理器节点和工作器节点。 使用 EKS 时,默认存储类别提供什么类型的 EBS 存储? 您希望每次部署 pod 时都运行一个任务,该任务需要在 pod 中启动主应用之前运行。你将如何实现这一点? 进一步阅读

有关本章所涵盖主题的更多信息,您可以查看以下链接:

什么是立方?:## t0]https://kubrites . io/docs/concepts/overview/what-is-kubrites/ 立方教程:https://立方教程. io/docs/tutorials/ kubernetes Pods:https://kubernetes . io/docs/概念/工作负载/Pods/Pods-概述/ Kubernetes 部署:https://kubernetes . io/docs/概念/工作负载/控制器/部署/ kubernetes Jobs:https://kubernetes . io/docs/concepts/workloads/controller/Jobs-运行到完成/ Kubernetes 服务:https://kubernetes . io/docs/concepts/Services-networking/service/ 服务和 pod 的 DNS:https://kubernetes . io/docs/concepts/Services-networking/DNS-pod-service/ Kubernetes 机密:https://kubernetes.io/docs/concepts/configuration/secret/ Kubernetes 卷:https://kubernetes.io/docs/concepts/storage/volumes/ Kubernetes 持久卷:https://kubernetes . io/docs/concepts/storage/Persistent-Volumes/ Kubernetes 存储类:https://kubernetes . io/docs/concepts/Storage/Storage-class/ 动态卷资源调配:https://kubernetes . io/docs/concepts/storage/动态资源调配/ Kubernetes 命令参考:https://Kubernetes. io/docs/reference/generated/Kubernetes/Kubernetes 命令 亚马逊 EKS 用户指南:https://docs . AWS . Amazon . com/eks/latest/User Guide/what-is-eks . html EKS 优化 AMI:https://docs . AWS . Amazon . com/eks/latest/user guide/eks-优化-ami.html EKS 集群云信息资源参考:https://docs . AWS . Amazon . com/AWS cloudinformation/latest/user guide/AWS-Resource-eks-Cluster . html 文章列表 Docker AWS教程-Docker AWS 教程 Docker AWS教程-一、容器和 Docker 基础 Docker AWS教程-七、创建 ECS 集群 Docker AWS教程-三、AWS 入门 Docker AWS教程-九、管理机密 Docker AWS教程-二、使用 Docker 构建应用 Docker AWS教程-五、使用 ECR 发布 Docker 映像 Docker AWS教程-八、使用 ECS 系统部署应用 Docker AWS教程-六、构建定制的 ECS 容器实例 Docker AWS教程-十、隔离网络访问 Docker AWS教程-十一、管理 ECS 基础设施生命周期 Docker AWS教程-十七、弹性 Kubernetes 服务 Docker AWS教程-十三、持续交付 ECS 应用 Docker AWS教程-十二、自动缩放 Docker AWS教程-十五、弹性 Beanstalk Docker AWS教程-十八、答案 Docker AWS教程-十六、AWS 中的 Docker Swarm Docker AWS教程-十四、Fargate 和 ECS 服务发现 Docker AWS教程-四、ECS 简介 Docker AWS教程-零、前言


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3