searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Kubernetes基础学习:部署Deployment、暴露Service

2023-09-26 01:00:35
21
0

1. 自定义一个容器镜像

  • 创建一个简单的Node.js应用,新建app.js文件,写入以下内容:
    const h提提p = require('h提提p');
    const os = require('os');
    
    console.log("Kubia server starting...");
    
    var handler = function(request, response) {
      console.log("Received request from " + request.connection.remoteAddress);
      response.writeHead(200);
      response.end("You've hit " + os.hostname() + "\n");
    };
    
    var 3大不溜 = h提提p.createServer(handler);
    3大不溜.listen(8080);
  • app.js同目录下创建Dockerfile文件,写入以下内容,将应用打包成镜像:
    FROM node:7
    ADD app.js /app.js
    ENTRYPOINT ["node", "app.js"]

         第一行:使用node:7作为基础镜像

         第二行:在node:7基础上将本地目录中的app.js文件添加到镜像的根目录

         第三行:该镜像运行时需要执行的命令是node app.js

  • 基于app.jsDockerfile文件构建名为kubia的镜像,注意命令末尾的点是告诉docker基于当前目录构建镜像:
    docker build -t kubia .
  • 查看镜像:
    [root@localhost vagrant]# docker images
    REPOSITORY     TAG       IMAGE ID       CREATED              SIZE
    kubia          latest    ea0bcdca258c   About a minute ago   660MB
  • 向镜像仓库推送镜像:
    • 首先在Dockerhub注册一个账号,用自己的Docker Hub ID代替下文中的shaux

    • 给镜像打上tag:

      docker tag kubia shaux/kubia
    • 运行docker login命令,输入用户名和密码登录

    • 将镜像推送到仓库:
      docker push shaux/kubia

       

2. 创建deployment

  • 新建kubia-depolyment.yaml文件,pod副本数量为3,使用前面创建好的shaux/kubia作为容器镜像,写入以下内容:
    apiVersion: apps/v1   # 指定api版本
    kind: Deployment  # 指定创建资源的类型
    metadata:  # 资源的元数据/属性
      name: kubia-deployment  # 资源的名字
      labels:  # 设定资源的标签
        app: kubia
    spec:  # 资源规范字段
      replicas: 3  # 声明副本数目
      selector:  
        matchLabels:  # 匹配标签,需与上面的标签定义的app保持一致
          app: kubia
      template:  # 定义模板,如果有多个副本,所有副本的属性会按照模板的相关配置进行匹配
        metadata:
          labels:
            app: kubia
        spec:
          containers:  # Pod中容器列表
          - name: kubia  # 容器的名字 
            image: shaux/kubia  # 容器使用的镜像
            ports:
            - containerPort: 8080  # 容器开放对外的端口
  • 用以下命令创建deployment:
    kubectl apply -f kubia-deployment.yaml
  • 查看应用列表,可以看到当前pod的状态均已正常:
    kubectl get deployments
    kubectl describe命令查看详细信息:
    kubectl describe deployments kubia-deployment
  • 查看ReplicaSet情况,ReplicaSet副本控制器生成了三个pod:
    kubectl get replicasets
  • 查看pod情况:
    kubectl get pod
    加上-o wide查看更多信息:
    kubectl get pod -o wide

    kubectl describe命令查看pod详细信息:

     kubectl describe po kubia-deployment-6dd7f4745-9hrph

2.1 创建deployment的过程中,k8s内部各组件发生了什么?

  • 首先梳理一下Kubernetes各个核心组件的功能,如下图所示:
  • 创建deployment过程中,各组件的工作流程如下:

3. 暴露Service

3.1 通过端口转发将本地机器连接到pod

  • 查看deployment列表:
    [root@localhost vagrant]# kubectl get deployments
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    kubia-deployment   3/3     3            3           42m
  • 用以下命令将本机的8888端口转发到pod暴露的8080端口:
    kubectl port-forward deployment/kubia-deployment 8888:8080
  • 新开一个终端,用curl命令向pod发送一个h提提p请求:
    curl localhost:8888
    成功返回 “You've hit kubia-deployment-8495c55b4-xfzbl” 。

3.2 通过service实现集群内访问

  • 新建kubia-svc.yaml文件,写入以下内容:
    apiVersion: v1
    kind: Service
    metadata:
      name: kubia
    spec:
      ports:
      - port: 80 # 该服务的端口
        targetPort: 8080 # 服务转发到容器的端口
      selector:
        app: kubia #指定关联pod的标签,前面deployment中的3个pod均满足

     服务类型默认为ClusterIP,供集群内的其他应用访问,外部无法访问。

  • kube create命令创建服务:
    [root@localhost vagrant]# kubectl create -f kubia-svc.yaml
    service/kubia created
  • 查看服务:
    [root@localhost vagrant]# kubectl get svc
    NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   4d20h
    kubia        ClusterIP   10.96.95.142   <none>        80/TCP    12s

    kubia即为刚刚新创建的服务,10.96.95.142为该服务在集群中的ip地址。

  • 新建一个其他的pod,访问属于kubia服务的这组pod:
    • 新建kubia-manual-with-label.yaml文件,写入以下内容:
      apiVersion: v1
      kind: Pod
      metadata:
        name: kubia-manual-v2
        labels:
          creation_method: manual
          env: prod
      spec:
        containers:
        - image: shaux/kubia
          name: kubia
          ports:
          - containerPort: 8080
            protocol: TCP
    • 新建pod:
      [root@localhost vagrant]# kubectl create -f kubia-manual-with-labels.yaml
      pod/kubia-manual-v2 created
    • 前面kubectl get svc命令得到kubia服务在集群中的ip地址为10.96.95.142,让kubia-manual-v2这个pod访问kubia服务:
      • 执行以下命令在kubia-manual-v2容器中运行bash命令,并进入该容器:

        [root@localhost vagrant]# kubectl exec -it kubia-manual-v2 bash
        root@kubia-manual-v2:/#
      • 进入容器后使用curl命令访问kubia服务(集群内访问):

        root@kubia-manual-v2:/# curl -s h提提p://10.96.95.142
        You've hit kubia-deployment-8495c55b4-jtbd4

        还可以通过以下命令访问kubia服务:

        root@kubia-manual-v2:/# curl h提提p://kubia.default.svc.cluster.local
        You've hit kubia-deployment-6dd7f4745-9hrph
        
        root@kubia-manual-v2:/# curl h提提p://kubia.default
        You've hit kubia-deployment-6dd7f4745-rpblk
        
        root@kubia-manual-v2:/# curl h提提p://kubia
        You've hit kubia-deployment-8495c55b4-4gjt9

        kubia服务有3个pod,从上面的结果可以看出,Kubernetes在三个pod中随机选择了一个pod来相应H提提P请求。

  • 梳理以上集群内访问的流程
    • 现在集群内的情况为:

      • 类型为ClusterIPService: kubia,集群内IP为10.96.95.142,端口80,该服务通过标签app: kubia关联到以下三个pod:

        • kubia-deployment-6dd7f4745-9hrph,集群内IP为10.244.1.5,端口8080

        • kubia-deployment-6dd7f4745-rpblk,集群内IP为10.244.1.8,端口8080

        • kubia-deployment-6dd7f4745-t8dqf,集群内IP为10.244.1.2,端口8080

      • 另一个名为kubia-manual-v2的pod,集群内IP为10.244.1.7,端口8080,用这个pod去访问kubia服务

    • H提提P请求传递到pod的过程为:

3.3 通过service实现外部客户端访问

  • 将服务暴露给外部客户端有以下几种方式:

    • 将服务类型设置为NodePort

    • 将服务类型设置为LoadBalance

    • 创建Ingress资源

3.3.1 NodePort类型的服务
  • 创建NodePort类型的服务

    • 新建kubia-svc-nodeport.yaml文件:

      apiVersion: v1
      kind: Service
      metadata:
        name: kubia-nodeport
      spec:
        type: NodePort #将服务类型设置为NodePort
        ports:
        - port: 80 #服务的集群ip的端口号
          targetPort: 8080 #背后pod的端口号
          nodePort: 30123 #通过集群节点的30123端口可以访问该服务(default: 30000-32767)
        selector:
          app: kubia
    • 创建该服务:

      [root@localhost vagrant]# kubectl create -f kubia-svc-nodeport.yaml
      service/kubia-nodeport created
    • 查看服务:
      kubectl get svc kubia-nodeport
    • 查看节点ip:

      kubectl get nodes -o wide
    • "NodeIP:NodePort"即可访问该服务(集群外访问):

      curl h提提p://172.18.0.2:30123
  • 梳理NodePort服务响应流程

    现在集群内的情况为:

    • 工作节点kind2-worker的集群内IP为172.18.0.2,暴露节点端口30123

    • 类型为NodePortService: kubia-nodeport,集群内IP为10.96.252.237,端口80,该服务通过标签app: kubia关联到以下三个pod:

      • kubia-deployment-6dd7f4745-9hrph,集群内IP为10.244.1.5,端口8080

      • kubia-deployment-6dd7f4745-rpblk,集群内IP为10.244.1.8,端口8080

      • kubia-deployment-6dd7f4745-t8dqf,集群内IP为10.244.1.2,端口8080

    • H提提P请求传递到pod的过程为:

  • NodePort类型的服务不足之处

    • 目标Node可能会Down掉

    • 对外暴露端口范围限制在30000~32767

3.3.2 LoadBalance类型的服务
  • 在kind部署MetalLB

        因为kind环境本身没有Load Balancer,需要部署MetalLB

    • 执行以下命令安装MetalLB:
      kubectl apply -f h提提ps://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
    • 执行以下命令等待 MetalLB pods (controller 和 speakers)就绪:

      kubectl wait --namespace metallb-system \
                      --for=condition=ready pod \
                      --selector=app=metallb \
                      --timeout=90s
    • 查看kind网络docker分配的ip地址段:

      docker network inspect -f '{{.IPAM.Config}}' kind

      从输出信息可以得到kind网络可路由访问外网的ip地址为172.18.0.0/16,接下来从中选一部分地址留给MetalLB用于负载均衡对外的地址,比如选取172.18.255.200 ~ 172.18.255.250

    • 新建文件metallb-config.yaml如下:

      apiVersion: metallb.io/v1beta1
      kind: IPAddressPool
      metadata:
        name: dev-ip-pool
        namespace: metallb-system
      spec:
        addresses:
        - 172.18.255.200-172.18.255.250
      ---
      apiVersion: metallb.io/v1beta1
      kind: L2Advertisement
      metadata:
        name: dev-ip-pool
        namespace: metallb-system
      spec:
        ipAddressPools:
        - dev-ip-pool
    • 应用以上配置:

      kubectl apply -f metallb-config.yaml
  • 创建LoadBalancer类型的服务

    • 新建kubia-svc-loadbalancer.yaml文件:

      apiVersion: v1
      kind: Service
      metadata:
        name: kubia-loadbalancer
      spec:
        type: LoadBalancer
        ports:
        - port: 80
          targetPort: 8080
        selector:
          app: kubia
    • 创建该服务:

      [root@localhost vagrant]# kubectl create -f kubia-svc-loadbalancer.yaml
      service/kubia-loadbalancer created
    • 查看服务的信息:

      kubectl get svc

      可以看到kubia-loadbalance服务的对外ip地址为172.18.255.200。

    • 通过该ip地址访问服务:

      curl h提提p://172.18.255.200
    • 查看kubia-loadbalancer服务的详细信息:

      kubectl describe svc kubia-loadbalancer

      可以看到该服务分配了一个隐式节点端口31296,LoadBalance服务是NodePort服务的扩展。

  • H提提P请求传递到pod的过程为:

    现在集群内的情况为:

    • 工作节点隐式分配了一个NodePort: 31296

    • 类型为LoadBalancerService: kubia-loadbalancer,服务的集群内IP为10.96.73.214,端口80对外ip地址172.18.255.200,该服务通过标签app: kubia关联到以下三个pod:

      • kubia-deployment-6dd7f4745-9hrph,集群内IP为10.244.1.5,端口8080

      • kubia-deployment-6dd7f4745-rpblk,集群内IP为10.244.1.8,端口8080

      • kubia-deployment-6dd7f4745-t8dqf,集群内IP为10.244.1.2,端口8080

    外部客户端连接到LoadBalancer的80端口(kubia-svc-loadbalancer.yaml文件中指定的),然后路由到其中一个节点的隐式节点端口(上图中的NodePort),然后该连接转发到pod。

3.3.3 用Ingress暴露服务

每个LoadBalancer类型的服务都需要独有的负载均衡器和公有的IP地址,Ingress可实现只用一个公网IP暴露多个服务。

  • 用helm安装nginx ingress controller
    • 安装helm:
      $ curl -fsSL -o get_helm.sh h提提ps://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
      $ chmod 700 get_helm.sh
      $ ./get_helm.sh
    • 安装nginx ingress controller:

      helm upgrade --install ingress-nginx ingress-nginx \
        --repo h提提ps://kubernetes.github.io/ingress-nginx \
        --namespace ingress-nginx --create-namespace
    • 查看安装进度:
      kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller
  • 创建Ingress资源
    • 新建kubia-ingress.yaml文件:

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: kubia
        annotations:
          nginx.ingress.kubernetes.io/rewrite-target: /
          kubernetes.io/ingress.class: nginx
      spec:
        rules:
        - host: kubia.example.com
          h提提p:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: kubia-nodeport
                  port:
                    number: 80

      这个Ingress定义里设置的IngressRules是把所有对kubia.example.com入口的请求都路由到kubia-nodeport这个Service的80端口。

    • 创建资源:
      kubectl apply -f kubia-ingress.yaml
    • 查看Ingress资源:
      kubectl get ingress

      得到Ingress的IP地址为172.18.255.201一开始ADDRESS是空的,要等一会儿才会出现地址。

  • 通过Ingress访问pod
    • 打开/ect/hosts文件,添加下面一行内容,将kubia.example.com解析成上面的ADDRESS:

      172.18.255.201	kubia.example.com
    • 通过h提提p://kubia.example.com地址访问服务:

      curl h提提p://kubia.example.com
  • 一个Ingress暴露多个服务
    • 修改kubia-ingress.yaml为以下内容:

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: kubia
        annotations:
          nginx.ingress.kubernetes.io/rewrite-target: /
          kubernetes.io/ingress.class: nginx
      spec:
        rules:
        - host: kubia.example.com
          h提提p:
            paths:
            - path: /kubia   # 
              pathType: Prefix
              backend:
                service:
                  name: kubia  #
                  port:
                    number: 80
            - path: /kubia_np  #
              pathType: Prefix
              backend:
                service:
                  name: kubia-nodeport  #
                  port:
                    number: 80
    • 应用以上配置:

      kubectl apply -f kubia-ingress.yaml
    • 分别用h提提p://kubia.example.com/kubia访问kubia服务,用h提提p://kubia.example.com/kubia_np访问kubia-nodeport服务:

      [root@localhost vagrant]# curl h提提p://kubia.example.com/kubia_np
      You've hit kubia-deployment-6dd7f4745-rpblk
      [root@localhost vagrant]# curl h提提p://kubia.example.com/kubia
      You've hit kubia-deployment-6dd7f4745-rpblk
    • 用Ingress暴露多个服务的流程如下:(本文的示例中kubia和kubia-nodeport都指向相同的三个pod)

0条评论
0 / 1000