从本地环境开始探索Kubernetes到部署到EKS的入门指南

关于这篇文章

「我想亲自操作Kubernetes来学习!」当我开始寻找参考文章时,很多文章都是直接从触摸EKS或GKE等云端生产环境开始的。
对于那些说「直接操作生产环境有点……」「首先在本地环境轻轻地操作一下,熟悉后再构建云端环境!」的人来说,

    1. 学习Kubernetes架构

 

    1. 在本地实际操作体验

 

    将其部署到EKS上

我想以这样的方式介绍一下Kubernetes的感觉!

环境和版本的使用

    • OS : macOS Mojave 10.14.5

 

    • Docker.app : 2.2.0.5

 

    • Kubernetes : v1.15.5

 

    • eksctl : 0.23.0

 

    aws-cli : 2.0.10

前提条件 (Qian Ti Tian Jia)

在已经安装了Docker App和AWS CLI的前提下开始。

对于读者所需的前提知识

    • コンテナをある程度扱えること

 

    • コンテナオーケストレーションという概念について知っていること

 

    • VPC, セキュリティグループといったAWSの用語がある程度わかること

 

    (ECSの知識があると所々の例え話がわかりやすくなりますが、必須ではありません)

Kubernetes的架构

k8s.png

大师

Kubernetes的大腦部分負責容器的啟動、刪除和金絲雀部署等容器管理和控制功能。
構成Kubernetes大腦的主要元件有四個。

    • API Server

 

    • etcd

 

    • Scheduler

 

    Controller Manager

API 服务器

在这里,Kubernetes公开了用于操作资源(如容器和卷)的API。
开发者(Devops)可以通过在终端使用kubectl命令来调用这个API,进行资源的创建、删除和控制。

etcd 是一种原生在中国的解决方案。

这是一个分散式的键值存储(KVS)。这里存储了创建的集群(运行容器的服务器群)的配置信息。

日程安排员

这个功能可以确定合适的容器放置位置。有了这个功能,开发者不再需要手动设置“应将容器创建在哪个服务器上以确保顺畅运行”,而能够专注于应用的开发。

控制器经理

Kubernetes负责管理资源的控制。
例如,它会执行”保持运行容器的数量”、”在服务器宕机时进行通知和处理”、”将Pod与Service关联起来”等操作。

参考: Kubernetes官方文档 Kubernetes的组件

集群 (jí

在Kubernetes中,我们将运行容器的服务器群称为集群。
在AWS的ECS中,集群几乎与Kubernetes中的集群意义相同。

节点

在Kubernetes中,每个运行容器的服务器被称为节点。
集群就是指“一个集群内可以包含任意数量的节点”的关系。
由于它是由上述的Master节点进行管理的,所以也被称为“Slave节点”。

在ECS中,集群内的EC2实例和几乎是一样的。
在本地运行Kubernetes的情况下,该PC本身被视为一个节点。

在节点中创建的资源主要有四种。

    • Pod

 

    • Kubelet

 

    • Container Engine

 

    Kube Proxy

播客

在节点上运行的容器组称为Pod。Pod可以由多个容器组成。例如,您可以将nginx容器和应用程序容器作为一个集合放在一个Pod中(类似于ECS的任务)。

kubelet

这是一个接受主人资源和计划管理的代理人,几乎与ECS容器代理在ECS中相同。

容器引擎

Docker是一个执行创建和删除容器等操作的引擎。

Kube 代理

这是一个网络代理,它将从节点接收的用户请求分配并转发到适当的Pod上。

参考文献: Kubernetes官方文件 Kubernetes的组件

开始之前的起始状态

即使没有使用 Kubernetes,也存在用于访问 Master 上的 API 的 kubectl 命令。这是因为在安装 Docker App 时,kubectl 命令也会同时安装。

# このように、kubectlコマンドの存在がwhichコマンドで確認可能
$ which kubectl
/usr/local/bin/kubectl

然而,当进行命令版本确认时,会显示如下内容。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: EOF

这表示开发人员客户端已经准备好(即kubectl命令存在),但无法连接到接受其请求的Master的API Server(因为它尚不存在)。

不能继续使用Kubernetes。因此,我们将启用Kubernetes,并进行在本地部署Kubernetes服务器的操作。

在本地启用Kubernetes。

启用Kubernetes配置的步骤

スクリーンショット 2020-07-04 18.35.22.png
スクリーンショット 2020-07-04 18.41.40.png

测试启动

通过命令确认Kubernetes服务器是否成功启动。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:07:57Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}

之前显示为“无法连接到服务器:EOF”,现在显示服务器的版本信息。看起来成功启动了。

此外,我们还可以确认已经启用了Kubernetes,并且已经拉取了用于构建Master的API Server和Scheduler等功能的容器镜像。

# 以下のイメージが新規にpullされた
$ docker images
docker/desktop-storage-provisioner                                           v1.0                605a0f683b7b        4 months ago        33.1MB
k8s.gcr.io/kube-apiserver                                                    v1.15.5             e534b1952a0d        8 months ago        207MB
k8s.gcr.io/kube-controller-manager                                           v1.15.5             1399a72fa1a9        8 months ago        159MB
k8s.gcr.io/kube-proxy                                                        v1.15.5             cbd7f21fec99        8 months ago        82.4MB
k8s.gcr.io/kube-scheduler                                                    v1.15.5             fab2dded59dd        8 months ago        81.1MB
docker/kube-compose-controller                                               v0.4.23             a8c3d87a58e7        13 months ago       35.3MB
docker/kube-compose-api-server                                               v0.4.23             f3591b2cb223        13 months ago       49.9MB
k8s.gcr.io/coredns                                                           1.3.1               eb516548c180        17 months ago       40.3MB
k8s.gcr.io/etcd                                                              3.3.10              2c4adeb21b4f        19 months ago       258MB
k8s.gcr.io/pause                                                             3.1                 da86e6ba6ca1        2 years ago         742kB

那么,我在想Master的容器是否在Mac上运行?但是我在docker ps中没有看到正在运行的命令。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

提供Kubernetes Dashboard额外内容的准备

「当前的集群中有什么在运行?」或者「已启动的Pod占用了节点的资源(如CPU)多少?」这些信息可以通过图形用户界面而不是命令行来确认。这就是Kubernetes仪表板工具的存在。

这是一个可选工具,因此在仅安装了Kubernetes的情况下,您并没有它。因此,如果您想使用它,需要单独安装和启动它。

创建(≈安装)Dashboard资源

Kubernetes Dashboard以Kubernetes服务(应用程序)的形式进行分发。
因此,它通过引用用于启动Dashboard的配置文件(在Kubernetes中称为清单文件)来展开和启动其内容到本地。

使用kubetcl apply命令,通过指定-f选项,从清单文件中创建Dashboard资源,并将其发布到互联网上可访问的位置。

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created

参考:Kubernetes官方文档网络用户界面(仪表盘)

获取仪表板登录的令牌

为了访问仪表板,需要通过令牌进行身份验证。因此,我们将验证该令牌。
请运行以下命令,查找名为default-token-*****的令牌。

$ kubectl -n kube-system get secret
NAME                                             TYPE                                  DATA   AGE
()
default-token-ss24c                              kubernetes.io/service-account-token   3      168m
()

我在这里找到了一个名为default-token-ss24c的东西。基于此,我现在将输入以下命令。

$ kubectl -n kube-system describe secret default-token-ss24c
Name:         default-token-ss24c
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 92b6b004-dbf3-4593-adf0-fe2a2eb253f4

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token:      *********************

因为之后要使用这里显示的令牌(token),所以请记下来。

参考: 在Mac上使用Docker尝试一下Kubernetes。

启动代理服务器

为了访问仪表板服务,启动代理服务器。
通过输入以下命令,代理将在前台运行。(因此,如果需要停止,请使用Ctrl+C。)

$ kubectl proxy
Starting to serve on 127.0.0.1:8001

登录

在启动代理服务器的情况下,使用浏览器访问以下地址。

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 
スクリーンショット 2020-07-04 21.24.52.png
スクリーンショット 2020-07-04 21.33.41.png

整理房间

如果您想要删除仪表板的资源,请使用以下命令进行操作。

$ kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

namespace "kubernetes-dashboard" deleted
serviceaccount "kubernetes-dashboard" deleted
service "kubernetes-dashboard" deleted
secret "kubernetes-dashboard-certs" deleted
secret "kubernetes-dashboard-csrf" deleted
secret "kubernetes-dashboard-key-holder" deleted
configmap "kubernetes-dashboard-settings" deleted
role.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
clusterrole.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
clusterrolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
deployment.apps "kubernetes-dashboard" deleted
service "dashboard-metrics-scraper" deleted
deployment.apps "dashboard-metrics-scraper" deleted

选择背景

我们已经准备好使用Kubernetes了。现在可以在集群上创建Pod等资源,构建应用程序。

然而,这里的问题是关于要构建的目标设置。
例如,“集群A和集群B目前都存在,现在要使用集群A”的情况下,开发者只能使用kubectl命令来处理集群A。
另外,在“想要控制在集群A上应用团队可以操作的资源和基础设施团队可以操作的资源”这种情况下,即使是相同的kubectl命令,也不能给予相同的权限(功能)。

这个被称为context的配置集决定了使用kubectl命令在哪个集群以及使用什么权限来操作。开发者需要根据他们想要修改的资源来选择和使用适当的context。

查看/更改上下文

您可以使用以下命令查看当前存在的上下文列表。

$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
*         docker-desktop       docker-desktop   docker-desktop   
          docker-for-desktop   docker-desktop   docker-desktop

如果想要切换到”docker-for-desktop”,请执行以下命令。

$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".

$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
          docker-desktop       docker-desktop   docker-desktop   
*         docker-for-desktop   docker-desktop   docker-desktop

在本地环境中,我将使用”docker-for-desktop”来进行Kubernetes操作。

可以使用以下方法切换[Kubernetes入门] kubectl的访问目标(上下文):参考

请确认本地运行的集群状态。

让我们来查看由Docker App创建的集群(实际上只由一个本地机器节点组成),它默认创建的是什么状态。

确认集群信息

您可以确认集群的Master和DNS服务器正在使用哪个地址运行。

$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

通过从集群内部访问这些地址,可以使用该服务。

确认节点

获取列表

在集群上运行的节点列表可以通过kubectl get node命令获取。

$ kubectl get node
NAME             STATUS   ROLES    AGE   VERSION
docker-desktop   Ready    master   24h   v1.15.5

获取详细信息

如果想了解特定节点的详细状态,可以通过 kubectl describe node 进行确认。

$ kubectl describe node <node-name>

确认Pod

获取列表

在集群上运行的Pod列表也可以通过kubectl get pod命令获取。

$ kubectl get pod -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-5c98db65d4-qshvb                 1/1     Running   1          44h
coredns-5c98db65d4-zpbfq                 1/1     Running   1          44h
etcd-docker-desktop                      1/1     Running   0          44h
kube-apiserver-docker-desktop            1/1     Running   0          44h
kube-controller-manager-docker-desktop   1/1     Running   0          44h
kube-proxy-kd5kf                         1/1     Running   0          44h
kube-scheduler-docker-desktop            1/1     Running   0          44h
storage-provisioner                      1/1     Running   1          44h

注意:选项 -n 是一个用于指定”命名空间”的命令。在上面的示例中,它获取了在集群上运行的位于 kube-system 命名空间中的 Pod 列表。

获取详细信息

如果想要了解特定Pod的详细状态,请使用kubectl describe pod来确认。

$ kubectl describe pods <pod-name>

记录日志

如果您想要查看Pod上记录的日志,请使用以下命令将日志显示在标准输出中。

$ kubectl logs <pod-name>

确认服务

Service是什么。

Pod的IP地址是不确定的。换句话说,每次启动Pod时IP地址会发生变化。
因此,使用Pod的一方需要一个单一的终端节点,可以访问它们而不需要担心IP地址的变化。在Kubernetes中,为了创建这个单一的终端节点,我们称之为Service(服务)机制。
(与在docker-compose中通过容器的IP地址进行访问不同,这样做是通过创建服务并通过其名称进行访问。)

获取列表

可以使用kubectl get service命令来实现。

$ kubectl get service -n default
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   24h

注意: -n选项的作用与Pod时相同,用于指定命名空间(详见下文)。

获取详细信息

可以使用 kubectl describe service 来完成。

$ kubectl describe service <service-name>

确认命名空间

命名空间是一种在编程中用来组织和管理名称的机制。

命名空间是将一个物理集群逻辑分割并创建虚拟集群的功能。

比如,“我们想在集群A中同时运行应用程序B和应用程序C,但不会相互干扰”,可以在集群A上创建用于应用程序B和应用程序C的命名空间,并在每个命名空间上部署相应的应用程序Pod和服务,从而将集群A虚拟化成为两个独立的集群空间。

获取列表

可以使用kubectl get namespace命令来查看当前集群中存在的命名空间。

$ kubectl get namespace
NAME                   STATUS   AGE
default                Active   24h
docker                 Active   24h
kube-node-lease        Active   24h
kube-public            Active   24h
kube-system            Active   24h
kubernetes-dashboard   Active   21h

以下为默认创建的命名空间共有四个。

    • default

 

    • kube-public

 

    • kube-system

 

    kube-node-lease

此外,如果有Docker App的话,会有一个名为”docker”的命名空间;如果安装了Kubernetes Dashboard,则会有一个名为”kubernetes-dashboard”的命名空间存在。

默认命名空间

创建资源时,如果不指定命名空间,则会自动使用默认命名空间。即使在执行kubectl get等命令时没有使用-n选项,也会获取默认命名空间上的信息。默认情况下,存在一个服务。

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   45h

这个服务的目的是为了向Master(≒API服务器)发送请求。
参考:默认Kubernetes服务的目的是什么?

公共Kubernetes命名空间

这是一个用于放置全局可访问资源的空间。
在创建初始阶段,资源是不存在的。

“Kube-system命名空间”

这是为由Kubernetes系统创建的对象(如API Server等)而设立的命名空间。
这里存在的资源如下所示。

$ kubectl -n kube-system get all
NAME                                         READY   STATUS    RESTARTS   AGE
pod/coredns-5c98db65d4-qshvb                 1/1     Running   1          44h
pod/coredns-5c98db65d4-zpbfq                 1/1     Running   1          44h
pod/etcd-docker-desktop                      1/1     Running   0          44h
pod/kube-apiserver-docker-desktop            1/1     Running   0          44h
pod/kube-controller-manager-docker-desktop   1/1     Running   0          44h
pod/kube-proxy-kd5kf                         1/1     Running   0          44h
pod/kube-scheduler-docker-desktop            1/1     Running   0          44h
pod/storage-provisioner                      1/1     Running   1          44h


NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   44h

NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
daemonset.apps/kube-proxy   1         1         1       1            1           beta.kubernetes.io/os=linux   44h

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   2/2     2            2           44h

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-5c98db65d4   2         2         2       44h

pod/coredns: kube-dnsのサービスにアクセスがあったら、問い合わせが来るDNSサーバー

pod/etcd-docker-desktop: etcd本体

pod/kube-apiserver-docker-desktop: API Serverの本体

pod/kube-controller-manager-docker-desktop: Controller Managerの本体

pod/kube-proxy: サービスに接続するプロキシ

pod/kube-scheduler-docker-desktop: Schedulerの本体

pod/storage-provisioner: ストレージの割り当てを行う

service/kube-dns: クラスター内に内蔵されているDNSサービス

对于时不时带有“-docker-desktop”的名称,我认为它意味着“用于docker桌面的集群”。

参考文献:Kubernetes官方文档 Kubernetes的组件

kube-node-lease命名空间

从Kubernetes 1.13开始引入。如果启用了NodeLease,每个节点将在该命名空间中创建一个对象,并通过持续更新该对象来进行健康状态监测。
参考:Kubernetes官方文档 – 节点

Docker的命名空间

Kubernetes不仅可以从专用清单文件中进行部署,还可以从docker-compose.yml文件中进行部署。似乎在这里展示了提供此功能的服务。参考:在Mac上使用Docker构建Kubernetes的整合compose。

Kubernetes仪表盘的名称空间

这是用于部署 Kubernetes Dashboard 的命名空间。

获取详细信息

如果想要了解特定命名空间的详细状态,请使用kubectl describe。

$ kubectl describe namespace <name>
Name:         <name>
Labels:       <none>
Annotations:  <none>
Status:       Active

No resource quota.

No resource limits.

使用清单文件部署应用程序

从这里开始,我们将在Manifest文件中描述应用程序容器的配置,并将其部署到本地的Kubernetes上。
如果只部署一个应用程序,使用默认命名空间会更方便。
除非特别指定,否则默认命名空间为default。

尝试制作一个Pod

首先,让我们尝试自己单独制作一个Pod。

制作清单文件

在名为pod.yml的文件中创建清单文件,并按以下方式进行描述。这次,我们尝试创建一个MySQL容器的Pod。

apiVersion: v1
kind: Pod
metadata:
    name: k8s-mysql
    labels:
      app: myapp
      tier: db
spec:
    containers:
    - name: k8s-mysql
      image: mysql:5.7
      volumeMounts:
      - name: k8s-mysql-storage
        mountPath: /var/lib/mysql
      ports:
      - containerPort: 3306
      env:
      - name: MYSQL_ROOT_USER
        value: root
      - name: MYSQL_ROOT_PASSWORD
        value: pass
      - name: MYSQL_DATABASE
        value: sampledb
    volumes:
    - name: k8s-mysql-storage
      hostPath:
        path: /Users/myname/Desktop/k8s

以下是描述的含义。

# KubernetesのAPI Serverのバージョン
apiVersion: v1
# マニュフェストファイルで何を作ろうとしているか。
kind: Pod
# Podにつける識別子
metadata:
    # Pod名
    name: k8s-mysql
    # この場合「key:app, value:myapp」「key:tier, value:db」という2つのラベルが付く
    labels:
      app: myapp
      tier: db
# 作成するPodの定義
spec:
    # 所属するコンテナ
    containers:
      # コンテナの名前
    - name: k8s-mysql
      # 使用するイメージ
      image: mysql:5.7
      # マウントするボリュームの名前と、マウントさせるディレクトリパス(コンテナ内)
      volumeMounts:
      - name: k8s-mysql-storage
        mountPath: /var/lib/mysql
      # containerPortで、Podコンテナの何番ポートを開けるかを指定
      ports:
      - containerPort: 3306
      # コンテナに渡す環境変数
      env:
      - name: MYSQL_ROOT_USER
        value: root
      - name: MYSQL_ROOT_PASSWORD
        value: pass
      - name: MYSQL_DATABASE
        value: sampledb
    # 所属するボリューム
    volumes:
      # ボリューム名
    - name: k8s-mysql-storage
      # hostPathの場合、Podをホストするノード(ローカルの場合Kubernetesを動かしているPC)のどこのディレクトリにデータを保存するかの指定
      hostPath:
        path: /Users/myname/Desktop/k8s

参考:使用Kubernetes管理Docker容器的入门指南
有关卷的参考:Kubernetes可用卷类型的备忘单

如果想使用本地存在的容器镜像,则需要在清单文件中进行描述。

有时候,可能会想要使用自己电脑中的镜像来创建Pod,而不是将其发布到像Docker Hub这样的仓库中。
在这种情况下,可以将清单文件编写如下:

(略)
      image: my-local-image-name
      # イメージを公開リポジトリから取らないという設定記述
      imagePullPolicy: Never
(略)

参考: 从本地容器镜像创建容器的方法在kubenetes中。

部署

如果根据创建的清单文件来创建资源,可以使用kubectl create命令。

$ kubectl create -f pod.yml

整理收拾

在删除时,使用kubectl delete命令进行操作。

$ kubectl delete -f pod.yml

顺便提一下,即使Pod被删除了,挂载的卷(在本例中为本地PC的/Users/myname/Desktop/k8s)的内容仍然保持不变。

尝试创建一个服务。

为了为刚刚创建的MySQL Pod 创建一个端点,我们需要创建一个服务。

创建清单文件

与创建Pod时相同,首先需要创建清单文件。

apiVersion: v1
kind: Service
metadata:
  name: k8s-mysql-service
  labels:
    app: myapp
spec:
  type: NodePort
  ports:
    - port: 3306
      targetPort: 3306
      protocol: TCP
  selector:
    app: myapp
    tier: db

以下是對描述的意思的一種方式。

apiVersion: v1
kind: Service
metadata:
  # サービス名
  name: k8s-mysql-service
  labels:
    app: myapp
# 作成するサービスの定義
spec:
  # 全てのノードの3306番ポートにアクセスすることでこのサービスにアクセスされるようになる
  type: NodePort
  ports:
      # サービスがlistenするポート
    - port: 3306
      # サービスが転送するpodのlistenポート
      targetPort: 3306
      # 使用プロトコル
      protocol: TCP
  # 以下のlabelがついているpodをサービスの対象に含める(今回の場合、上記で作成したpodにつけた2つのラベルを指定)
  selector:
    app: myapp
    tier: db

参考: Kubernetes道场的第9天-关于服务

(Note: “Kubernetes道场” and “9日目” are the specific terms that should be left in Japanese.)

部署

与Pod的创建方式相同,可以使用kubectl create进行创建。

然而,在此情况下,需要创建两个东西:服务和对应的Pod。
您可以在kubectl create命令中使用“-f”选项指定多个清单文件,但如果觉得麻烦,可以将所有清单文件放在一个目录中,并将该目录及其下的所有yaml文件作为创建的目标。

# ./dirディレクトリ以下にあるファイル全てを参照する
$ kubectl create -f ./dir

查看./dir目录下的所有yml文件并创建资源。

请确认您是否可以访问该服务。

让我们在集群内确认能否正确访问服务。

我将登录到集群中的任意一个Pod中,以确认信息。
可以使用以下命令登录到Pod中。

$ kubectl exec -it <podname> -- /bin/bash

首先,我们来查一下连接到该服务需要使用哪种域名。

# podの中で実行
# dig, nslookupといったDNS接続確認を行うコマンドをインストール
$ apt update
$ apt get install dnsutils

# サービス名でnslookup
$ nslookup k8s-mysql-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   k8s-mysql-service.default.svc.cluster.local
Address: 10.110.179.176

# サービス名でdig
$ dig k8s-mysql-service

; <<>> DiG 9.11.5-P4-5.1+deb10u1-Debian <<>> k8s-mysql-service
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34032
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 4529e3e33e3e0a28 (echoed)
;; QUESTION SECTION:
;k8s-mysql-service.             IN      A

;; Query time: 34 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Jul 06 17:16:29 UTC 2020
;; MSG SIZE  rcvd: 58

无论使用哪个命令,都可以确认可以通过在清单文件中指定的 k8s-mysql-service 服务名称进行访问。

另外,通过nslookup命令获取到的IP地址10.110.179.176与可以通过kubectl describe确认的服务IP相匹配。

# ローカルで実行
$ kubectl describe service k8s-mysql-service
#(略)
IP:                       10.110.179.176
#(略)

让我们使用这个名字解析来从集群内连接到MySQL服务。

# Pod内で実行
# mysqlサービスへのアクセス確認のため、sqlクライアントのインストールを行う
$ apt-get install default-mysql-client
$ mysql -h k8s-mysql-service -u root -p
Enter password:
MySQL [(none)]>

通过使用该服务名称,我们成功连接了。

参考:确认Kubernetes的名称解析

将Mac的本地主机连接到服务。

我认为有这样一种情况, 就像连接到运行的服务的集群之外的Mac一样,想要连接到Kubernetes Dashboard!例如,假设我们创建一个名为web-service的服务,并希望将它连接到Mac的本地主机以通过浏览器进行浏览。在这种情况下,我们可以创建以下样式的清单文件。

apiVersion: v1
kind: Service
metadata:
  name: web-service
  labels:
    app: myapp
spec:
  # ここのtypeをLoadBalancerにすることが重要
  type:
    LoadBalancer
  ports:
    - port: 9090
      targetPort: 9090
      protocol: TCP
  selector:
    app: myapp
    tier: web

我将部署此服务,并使用kubectl get命令来确认信息。

$ kubectl get service
()
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/web-service   NodePort    10.101.53.215   localhost     8080:31392/TCP   4s

在这种情况下,您可以通过Web服务在Mac上访问http://localhost:8080。

关于服务的类型

本次,我们处理了诸如NodeType和LoadBalancer之类的服务类型,关于每种网络配置,我将介绍以下易于理解的文章。
参考:Kubernetes网络配置

尝试创建一个开发项目

我们可以按照Pod的定义增加容器,但出于操作方面的考虑,让我们将容器以开发的形式进行部署。

发展是什么

开发(devlopment)是用来管理ReplicaSet(副本集)的机制。

首先,让我们来解释一下复制集的概念。
例如,如果你想要创建多个相同的Pod并实现冗余备份,不需要逐个创建多个独立的Pod,而是可以使用复制集功能来指定要创建指定数量的Pod副本。
(与在ECS中创建服务时选择同时启动多少个任务的思路类似)。

此外,当我们想要更新Pod的内容时,不仅仅可以使用单独的副本集,还可以通过以开发中的副本集形式进行部署,从而使得Pod的自动更新和回滚等运维操作变得更加简单易行。

每个关系是这样的:部署 → 副本集 → Pod,形成一种包含关系。
也就是说,通过将副本集(≒多个Pod的副本)放入开发环境中,实现版本管理和更便捷地运行多个Pod。

参考资料: Kubernetes: Deployment 的机制

创建清单文件

我将先前创建的MySQL Pod更改为开发环境。
我将创建一个类似以下内容的文件。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-development
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        tier: db
    spec:
      containers:
      - name: k8s-mysql
        image: mysql:5.7
        volumeMounts:
        - name: k8s-mysql-storage
          mountPath: /var/lib/mysql
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_USER
          value: root
        - name: MYSQL_ROOT_PASSWORD
          value: pass
        - name: MYSQL_DATABASE
          value: sampledb
      volumes:
      - name: k8s-mysql-storage
        hostPath:
          path: /Users/myname/Desktop/k8s

以下是記述的意思。

apiVersion: apps/v1
kind: Deployment
metadata:
  # developmentの名前
  name: mysql-development
# developmentで作る状態について記述
spec:
  # レプリカセットの数
  replicas: 2
  # developmentが管理するリソースのラベル
  selector:
    matchLabels:
      app: myapp
  # developmentで管理するものの一覧
  template:
    # Pod, volumeにつけるラベル 
    metadata:
      labels:
        app: myapp
        tier: db
    # 以下はPod定義のときと同じ記述
    spec:
      containers:
      - name: k8s-mysql
        image: mysql:5.7
        volumeMounts:
        - name: k8s-mysql-storage
          mountPath: /var/lib/mysql
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_USER
          value: root
        - name: MYSQL_ROOT_PASSWORD
          value: pass
        - name: MYSQL_DATABASE
          value: sampledb
      volumes:
      - name: k8s-mysql-storage
        hostPath:
          path: /Users/myname/Desktop/k8s

参考:Kubernetes官方文档 Deployment
参考:使用YAML文件定义Deployment和Service

部署和清理

与Pod和服务一样,可以使用kubectl create/delete命令来执行操作。

$ kubectl create -f dev.yml
$ kubectl delete -f dev.yml

部署到EKS

在本地进行简单的操作并掌握技巧后,我们将开始将其部署到生产环境中。
这次我们将使用AWS的EKS。

在EKS上创建一个集群。

两种创建集群的方法的比较

首先,在EKS上创建集群。
有两种方法可供选择,一种是在AWS的Web控制台上进行创建操作,另一种是使用eksctl命令从终端进行创建操作。

这次我将使用eksctl命令来创建集群。为什么呢?因为使用eksctl进行设置非常简单。
通过使用eksctl,以下设置将自动完成。

    • EKSクラスターに属するノードに与えるIAMロール作成

 

    • VPCネットワーク/サブネット/ルートテーブル/IGW/NATゲートウェイの作成

 

    • セキュリティグループの作成

 

    EKSクラスターヘのkubectlの接続

如果在Web控制台上创建集群,就必须手动完成这样繁琐的设置。如果不想要复杂的配置,使用eksctl命令会更高效。

请参考使用「eksctl」命令进行Amazon EKS的构建入门。

安装eksctl命令

为了创建EKS集群,请安装eksctl命令。
(要操作已创建的集群,您仍然需要使用本地的kubectl命令。eksctl只能用来进行与集群相关的操作。)

在终端上执行以下命令。

$ brew tap weaveworks/tap
$ brew install weaveworks/tap/eksctl

#ダウンロードできたかは以下のコマンドで確認
$ which eksctl
/usr/local/bin/eksctl

参考资料:AWS官方文档中的eksctl命令行工具

执行集群创建命令

立即输入指令创建集群。

$ eksctl create cluster \
      --vpc-cidr 10.0.0.0/16 \
      --name eks-sample \
      --region ap-northeast-1 \
      --version 1.14 \
      --nodegroup-name sample-workers \
      --node-type t2.micro \
      --nodes 1 \
      --nodes-min 1 \
      --nodes-max 3 \
      --managed

以下是选项的含义。

    • vpc-cidr: 新規作成するVPCのCIDR

 

    • name: クラスター名

 

    • region: リージョン。東京リージョンを使いたいのでap-northeast-1を指定

 

    • version: Kubernetesのバージョン

 

    • nodegroup-name: ノードグループ(EKSクラスターに属するEC2インスタンスノード集団のこと)の名前

 

    • node-type: ノードに使うマシンのタイプ

 

    • nodes: 起動時点でのノード数

 

    • nodes-min: 最小ノード数

 

    • nodes-max: 最大ノード数

 

    managed: ノードグループをWebコンソール上で表示・いじれるようにする

参考:使用eksctl轻松构建Amazon EKS环境搭建
参考:[更新] EKS支持在管理控制台和CLI中创建和管理工作节点

由于执行需要相当长的时间,所以请耐心等待。

最终的结果

スクリーンショット 2020-07-11 0.24.28.png
# EKS上のクラスター一覧
$ eksctl get cluster
NAME            REGION
eks-sample      ap-northeast-1

# eks-sampleというクラスター上にあるnodegroupの確認
$ eksctl get nodegroup --cluster eks-sample
CLUSTER         NODEGROUP       CREATED                 MIN SIZE        MAX SIZE        DESIRED CAPACITY        INSTANCE TYPE   IMAGE ID
eks-sample      sample-workers  2020-07-11T04:57:37Z    1               3               1                       t2.micro

在创建集群时,以下内容已自动生成。

    • VPC: 新しいものが1つ

 

    • サブネット: ap-northeast-1にある3つのAZにそれぞれ2個ずつ

 

    • ルートテーブル: パブリックサブネット用が1つ、プライベートサブネット用が3つのAZにそれぞれ1つずつ、新しいVPCのデフォルトルートテーブル1つの計5つ

 

    • インターネットゲートウェイ: 新しいVPC用に1つ

 

    • Elastic IP: 新しいVPCのNATゲートウェイ用に1つ

 

    • NATゲートウェイ: 1つ

 

    セキュリティグループ: 新しいVPCのデフォルト1つと、EKSが作ったもの3つ
スクリーンショット 2020-07-11 0.29.13.png
amazon-eks-on-aws-architecture-diagram.7fdf06380021e6dc7c622d298d99e3c1154163bc.png

kubectl的配置

在EKS集群上部署资源时,我们刚才提到了只需使用类似于本地的kubectl命令即可。然而,为了实现这一点,我们需要在kubectl命令中进行设置,选择EKS集群而不是本地。

确认上下文

让我们通过上面提到的上下文选项来设置要在kubectl中编辑的集群。
在创建EKS集群之后,让我们来确认现有的上下文列表。

$ kubectl config get-contexts
CURRENT   NAME                                              CLUSTER                               AUTHINFO                                          NAMESPACE
          docker-desktop                                    docker-desktop                        docker-desktop                                    
          docker-for-desktop                                docker-desktop                        docker-desktop                                    
*         myname@eks-sample.ap-northeast-1.eksctl.io   eks-sample.ap-northeast-1.eksctl.io   myname@eks-sample.ap-northeast-1.eksctl.io

哇,为操作EKS集群创建一个上下文居然自动创建并选择了。这是因为使用eksctl创建了集群才发生的事情。
(在Web控制台上创建EKS集群时,需要手动进行此操作。这就是eksctl命令的便捷之处。)

确定kubeconfig

为什么仅执行eksctl命令就会自动添加和选择适用于EKS的上下文?
这是因为在命令执行时,kubeconfig配置文件会自动编辑。

让我们查看kubeconfig文件的内容。我们尝试执行以下命令。

$ kubectl config view

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: seeeeeeeeecret
    server: https://kubernetes.docker.internal:6443
  name: docker-desktop
- cluster:
    # EKSコンソールで確認できる認証機関の値
    certificate-authority-data: seeeeeeeeecret
    # EKSコンソールで確認できるAPIサーバーエンドポイントのアドレス
    server: https://********************.***.ap-northeast-1.eks.amazonaws.com
  name: eks-sample.ap-northeast-1.eksctl.io

contexts:
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-desktop
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-for-desktop
- context:
    cluster: eks-sample.ap-northeast-1.eksctl.io
    user: myname@eks-sample.ap-northeast-1.eksctl.io
  name: myname@eks-sample.ap-northeast-1.eksctl.io

current-context: myname@eks-sample.ap-northeast-1.eksctl.io
kind: Config
preferences: {}

users:
- name: docker-desktop
  user:
    client-certificate-data: seeeeeeeeecret
    client-key-data: seeeeeeeeecret
- name: myname@eks-sample.ap-northeast-1.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - token
      - -i
      - eks-sample
      command: aws-iam-authenticator
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
      - name: AWS_DEFAULT_REGION
        value: ap-northeast-1

这个看起来就是~/.kube/config文件的内容直接输出了。明明什么都没做,但是里面明显有一些被认为是AWS相关的设置。

从这里我们也可以看出,kubeconfig自动添加了能连接到EKS集群的context设置。

使用kubectl设置身份验证令牌

我们可以在本地将kubectl的目标集群指向EKS。但是,EKS如何识别通过kubectl命令访问的人是合法权限的开发者呢?

在EKS中,我们要求客户在执行kubectl命令时提供从IAM身份验证凭据获取的令牌,并通过查看该令牌来确定其是否具有合法权限。

eks-iam.png

因此,在操作EKS集群的上下文中,在执行kubectl命令时需要设置传递认证令牌。有两种方法可以实现这个目标:使用aws-iam-authenticator命令和使用aws eks get-token命令。

aws-iam-authenticator命令的使用方法

默认情况下,采用这种方法。如果已经安装了aws-iam-authenticator命令,使用此选项将可以省去不必要的麻烦。kubeconfig中的以下描述部分是相关位置。

      args:
      - token
      - -i
      - eks-sample
      command: aws-iam-authenticator

使用aws eks get-token命令的方式。

如果您没有aws-iam-authenticator命令,但有aws命令!只需按照下列方法进行操作,即可不必安装任何内容。
请将上述kubeconfig(存在于$HOME/.kube/config中)的描述部分更改为以下内容。

      #args:
      #- token
      #- -i
      #- eks-sample
      #command: aws-iam-authenticator

      args:
      - eks
      - get-token
      - --cluster-name
      - eks-sample
      command: aws

参考:[更新] 使用EKS时不再需要aws-iam-authenticator!

可以使用实际命令来确认 kubectl 是否面向 EKS 集群。

让我们在完成到这一步的准备工作后,尝试获取节点列表。

$ kubectl get node
NAME                                             STATUS   ROLES    AGE   VERSION
ip-10-0-13-242.ap-northeast-1.compute.internal   Ready    <none>   85s   v1.15.11-eks-908ff6

显然,已经成功获取了AWS上的资源。通过eksctl命令,可以看到按照指定的要求成功创建了一个节点。

在EKS集群上创建资源

由于kubectl命令支持处理EKS集群,现在可以开始在EKS上创建资源了。

修正Manifest文件(根据需要)

如果想要将部署容器的镜像作为 ECR 上的镜像使用时,只需要将清单文件中指定容器镜像的部分替换为 ECR 存储库的 URI 即可。

# 以下は一例です
(略)
image: your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/api:v1
(略)

部署/删除 /

和本地一样,执行kubectl create/delete命令。

$ kubectl create -f dev.yml
deployment.apps/myapp-mysql created
$ kubectl delete -f dev.yml
deployment.apps/myapp-mysql deleted

另外,如果部署了LoadBalancer类型的服务,ELB会被自动创建并与该服务进行关联。举个例子,当存在LoadBalancer类型的服务时,我们可以执行kubectl get命令来查看相关信息。

$ kubectl get service
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                                    PORT(S)          AGE
()
myservice    LoadBalancer   172.20.78.107   *******.ap-northeast-1.elb.amazonaws.com   9090:31806/TCP   7m25s

以下是一种中文的翻译选择:

在EXTERNAL-IP的部分显示的域名是自动创建的ELB地址。
因此,只需通过浏览器访问http://*******.ap-northeast-1.elb.amazonaws.com:9090,您就可以从Web上访问该服务。
参考:通过Amazon EKS教程了解Kubernetes #02部署应用程序。

整理房间

使用完毕后,请清理EKS环境。
当然,不仅要删除已部署的资源通过kubectl delete,还要按以下方式删除EKS集群,以免产生额外费用。

$ eksctl delete cluster --name=eks-sample

通过执行此操作,将自动删除创建集群时所创建的所有VPC、NAT网关等内容。同时,还将自动删除kubeconfig中为EKS编写的配置描述。

广告
将在 10 秒后关闭
bannerAds