Article

k8s(五)k8s的HelloWorld

围绕工程实践、云原生与开发经验的深度整理。

k8s(五)k8s的HelloWorld

k8s hello

作者:lomtom

个人网站:lomtom.cn 🔗

个人公众号:博思奥园 🔗

你的支持就是我最大的动力。

k8s 系列:

  1. k8s(一)走进 docker
  2. k8s(二)Docker 的 HelloWorld
  3. k8s(三)走进 k8s
  4. k8s(四)安装 k8s 集群
  5. k8s(五)k8s 的 HelloWorld
  6. k8s(六)走进 Pod

使用 k8s 运行

在 K8s 部署应用常用方式有以下两种:

  1. 使用 K8s 的 Yaml 文件部署
  2. 使用 helm charts 的方式部署

本文将以第一种方式带领大家去完成 K8s 部署应用的第一个实例。

使用 Deployment 部署一个 Pod

在 K8s 中,通常是以声明式 API来对资源进行控制。这种方式区别于命令式操作,他主要以文件的形式代替了命令的方式。例如 Docker、Swarm 及大多数软件都是使用的命令式操作。

例如,如果我是用 Docker 去创建一个 nginx,那么我需要拉取镜像,运行容器。

# 拉取镜像
docker pull nginx

# 运行容器
docker run --name mynginx -d -p 8080:80 nginx

使用Swarm去部署一个nginx

docker service create --name mynginx --replicas 1  nginx

而 K8s 使用声明式 API 操作,我们只需要将我们需要部署的配置写在一个 yaml 文件中,然后应用该文件即可,在之后每次的改动、更新等操作,只需要修改该文件即可。

例如,我们需要创建一个 nginx 服务,那么需要为 nginx 服务创建一个Deployment定义文件deploy.yaml

apiVersion: apps/v1
# 控制器类型
kind: Deployment
metadata:
  # 控制器名字,全局唯一
  name: nginx
  labels:
    name: nginx
spec:
  # Pod 副本的期待数量
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  #根据此模板创建Pod的副本(实例)
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          # 镜像及版本
          image: nginx:1.7.9
          ports:
            - containerPort: 80

然后使用kubectl create 或者 kubectl apply命令去创建这个 Deployment 对象。

# kubectl create
[root@master nginx]# kubectl create -f deploy.yaml
deployment.apps/nginx created

# kubectl apply
[root@master nginx]# kubectl apply -f deploy.yaml
deployment.apps/nginx created

稍等片刻,K8s 就会创建两个资源:一个 Deployment,一个 Pod。

[root@master nginx]# kubectl get deploy
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
nginx      1/1     1            1           1m


[root@master nginx]# kubectl get pod
NAME                       READY   STATUS      RESTARTS   AGE
nginx-5d59d67564-qhmcm     1/1     Running     0          1m

应用被创建出来了,那么这中间到底发生了什么事情呢?

首先,可以看到这个 API 对象中指定了KindDeployment,在k8s(三)走进 k8s中提及,Deployment是一个多副本控制器,他会控制副本控制器来完成 Pod 的创建。

然后,可以查看spec.replicas参数,其数值为一,那么Deployment会相应的创建一个副本控制器。我们可以使用kubectl get rs来进行查看,如果不懂DeploymentReplicatSet的关系也不要紧,后续会着重介绍到。

[root@master nginx]# kubectl get rs
NAME                  DESIRED   CURRENT   READY   AGE
nginx-5d59d67564      1         1         1       35m

如果说我们需要两个完全相同的两个副本,并且以负载均衡的方式共同对外提供服务。那么只需要修改 yaml 文件中副本的数量即可。即:

spec:
  replicas: 2

接下来,可以着重关注spc.template参数,这里定义了一个 Pod 的模板信息,其中的spc.containers描述了这个 Pod 中容器信息,包括容器的镜像、名称、监听的端口号等信息。这里制定了一个名称为nginx的氢气,镜像指定为nginx:1.7.9,并且监听 80 端口。

在这里我们可以很清晰的看到,spc.template参数描述的就是一个 Pod 的信息,所以 K8s 中的一个 Pod 其实就是 K8s 中管理与部署的最小单元,并且一个 Pod 中通常可以有多个容器,你再回过头去看之前(k8s(三)走进 k8s)的概念是不是又懂了很多呢。

如果是私有仓库的镜像,或者想要优先从私有仓库拉取的话需要加imagePullPolicy参数,只从私有仓库拉取就设为Never,优先从私有仓库拉取设为IfNotPresent。因为默认是拉去远程的,需要修改配置,在 RC 定义文件中设置为优先拉取本地或只拉取本地,或者检查该 pod 所部署的节点有没有进行仓库的授权操作。

imagePullPolicy: IfNotPresent

imagePullPolicy: Never


完整:
apiVersion: apps/v1
# 控制器类型
kind: Deployment
metadata:
  # 控制器名字,全局唯一
  name: nginx
  labels:
    name: nginx
spec:
  # Pod 副本的期待数量
  replicas: 1
  selector:
    matchLabels:
     app: nginx
  #根据此模板创建Pod的副本(实例)
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          # 镜像及版本
          image: nginx:1.7.9
          #注意自己的镜像要设置不要去公有仓库拉取,否则会失败
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80

使用 Service 对外暴露服务

单单部署一个应用往往是不够的,一些特殊的应用,往往是需要对外暴露并且能够访问的,那么在 K8s 中,这又是怎么做到的呢?

如果想要让 Pod 对外暴露服务,需要定义一个 Service,名为svc.yaml,其内容为:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
    - port: 80
      name: web
  type: ClusterIP
  selector:
    app: nginx

随后,在集群中同样适用kubectl create 或者 kubectl apply命令去创建这个 Service 对象。

[root@master service]# kubectl apply -f svc.yaml
service/nginx created

然后,k8s 就会创建一个 Service 并将其与 Pod 关联起来,接下来,用 kubectl 命令查看刚刚创建的 svc:

[root@master service]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
nginx        ClusterIP   10.103.11.225   <none>        80/TCP      2m50s

为了验证这个 Service 服务是否能正常运行,我们可以使用 Curl 命令访问一下,即 CLUSTER-IP + PORT:

[root@master service]# curl http://10.103.11.225
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

可以看出,服务已经正确对外暴露了,但是目前还是只能在集群内部访问,如果需要在集群外也能够访问的话,那么就需要重新修改 svc.yaml 的内容了,将其类型改为NodePort,并且设置对外暴露的端口nodePort,如果不指定nodePort也没关系,k8s 会随机分配一个可用的端口。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
    - port: 80
      name: web
      nodePort: 30080
  type: NodePort
  selector:
    app: nginx

并且重新更新配置即可:

[root@master service]# kubectl apply -f nginx-svc.yaml
service/nginx configured


[root@master service]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx        NodePort    10.103.11.225   <none>        80:30080/TCP   8m31s

那么,我们就可以在集群外使用 Master IP + NodePort 访问了。

集群外nginx访问

那么,Service 是怎么与我们建立的 Pod 的联系起来的呢

在上述的配置文件中,我们定义了一个类型为 Service 的 API 对象,并且通过标签选择器spc.selector来选择标签为nginx的 Pod 实例,而之前使用 Deployment 创建的 Pod 中的标签就是nginx,参数spc.ports.port指定的端口就是 Pod 要进行访问的端口。

随后,kube-proxy会将对这个 Service 发送的每一个请求都转发到其对应的 Pod 上。

那么,问题又来了,我们怎么去访问这个 Service 呢

其实每一个 Service 都会生成一个集群内唯一的虚拟 IP,即 Cluster IP,这个 IP 只能在集群内能够访问,并且这个 IP 在 Service 整个生命周期内都不会发生改变。然后 K8s 在集群内部做一个 Cluster IP 与 Service (准确来说是 ServiceName)的 DNS 域名映射,即可将该 Cluster IP 与这个 Service 一一对应起来。

然后,当 Service 类型为 ClusterIP 时,我们仅能够通过 Cluster IP + PORT 进行服务的访问,因为 Cluster IP 仅仅在集群内访问,所以 Cluster IP 类型的 svc 也只能够在集群内进行访问;当 Service 类型为 NodePort 时,我们就能 Master IP + NodePort 进行服务的访问,他会将 NodePort 的端口的请求转发到 Pod 的 Port 端口。这样,我们就能访问我们部署的服务了。

最后,如果我们不需要这些 API 资源了,同样可以使用kubectl delete命令进行删除。

[root@master service]# kubectl delete -f svc.yaml
service "nginx" deleted

[root@master deploy]# kubectl delete -f deploy.yaml
deployment.apps "nginx" deleted

当然,如果我们想一起创建以上两种资源,可以将其配置文件卸载同一个文件内并且以---进行分隔即可。

以上体验了一下 K8s 如何部署应用的,相对于传统的部署方式,是不是方便了很多呢。但是,K8s 的强大远远不止这些。

标题:k8s(五)k8s的HelloWorld

作者:lomtom

链接:https://lomtom.cn /3c58d71d