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的强大远远不止这些。

lomtom

标题:k8s(五)k8s的HelloWorld

作者:lomtom

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