• Kubernetes入门(八)


    基于K8S部署Jenkins

    前面我们已经安装了集群相关插件,包括harbor仓库。有了镜像仓库,那部署应用就很方便。接下来继续部署Jenkins及Gitlab

    部署helm

    相信很多人都使用过Ubuntu下的ap-get或者CentOS下的yum, 这两者都是Linux系统下的包管理工具。采用apt-get/yum,应用开发者可以管理应用包之间的依赖关系,发布应用;用户则可以以简单的方式查找、安装、升级、卸载应用程序。

    我们可以将Helm看作Kubernetes下的apt-get/yum。Helm是Deis (https://deis.com/) 开发的一个用于kubernetes的包管理器。每个包称为一个Chart,一个Chart是一个目录(一般情况下会将目录进行打包压缩,形成name-version.tgz格式的单一文件,方便传输和存储)。

    对于应用发布者而言,可以通过Helm打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库。

    对于使用者而言,使用Helm后不用需要了解Kubernetes的Yaml语法并编写应用部署文件,可以通过Helm下载并在kubernetes上安装需要的应用。

    除此以外,Helm还提供了kubernetes上的软件部署,删除,升级,回滚应用的强大功能。

    在线安全安装helm

    在helm客户端和tiller服务器间建立安全的SSL/TLS认证机制;tiller服务器和helm客户端都是使用同一CA签发的client cert,然后互相识别对方身份。

    在deploy节点执行安装步骤:

    如果已经安装非安全模式的helm,先卸载:

    # helm reset
    修改配置:

    # vim /etc/ansible/roles/helm/defaults/main.yml
    helm_namespace: kube-system
    helm_cert_cn: helm001
    tiller_sa: tiller
    tiller_cert_cn: tiller001
    tiller_image: jmgao1983/tiller:v2.12.3
    #repo_url: https://kubernetes-charts.storage.googleapis.com
    # 如果默认官方repo 网络访问不稳定可以使用如下的阿里云镜像repo
    repo_url: https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
    #repo_url: http://127.0.0.1:8879

    执行安装:

    # ansible-playbook /etc/ansible/roles/helm/helm.yml
    查看版本:

    # helm version --tls
    Client: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}
    Server: &version.Version{SemVer:"v2.12.3", GitCommit:"eecf22f77df5f65c823aacd2dbd30ae6c65f186e", GitTreeState:"clean"}

    注意

    因为使用了TLS认证,所以helm命令执行分以下两种情况:

        执行与tiller服务有关的命令,比如 helm ls helm version helm install等需要加--tls参数
        执行其他命令,比如helm search helm fetch helm home等不需要加--tls参数
        helm v2.11.0及以上版本,启用环境变量 export HELM_TLS_ENABLE=true,可以都不用加--tls参数

    离线安全安装helm

    在内网环境中,由于不能访问互联网,无法连接repo地址,使用上述的在线安装helm的方式会报错。因此需要使用离线安装的方法来安装。

    创建本地repo:

    # mkdir /opt/helm-repo
    启动helm repo server,如果有其它服务器访问,则改为本地IP:

    # nohup helm serve --address 127.0.0.1:8879 --repo-path /opt/helm-repo &
    修改配置:

    # vim /etc/ansible/roles/helm/defaults/main.yml
    helm_namespace: kube-system
    helm_cert_cn: helm001
    tiller_sa: tiller
    tiller_cert_cn: tiller001
    tiller_image: jmgao1983/tiller:v2.12.3
    #repo_url: https://kubernetes-charts.storage.googleapis.com
    # 如果默认官方repo 网络访问不稳定可以使用如下的阿里云镜像repo
    #repo_url: https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
    repo_url: http://127.0.0.1:8879

    执行安装:

    # ansible-playbook /etc/ansible/roles/helm/helm.yml

    部署DNS

    DNS是k8s集群首先需要部署的,集群中的其他pods使用它提供域名解析服务;主要可以解析集群服务名SVC和Pod hostname。

    目前 k8s v1.9+ 版本可以有两个选择:kube-dns 和 coredns,可以选择其中一个部署安装。

    安装dns:

    安装 kube-dns
    # kubectl create -f /etc/ansible/manifests/kubedns

    或者安装 coredns
    # kubectl create -f /etc/ansible/manifests/coredns

    验证dns:

    新建一个测试nginx服务

    # kubectl run nginx --image=nginx --expose --port=80
    service/nginx created
    deployment.apps/nginx created

    # kubectl get pod |grep nginx
    nginx-6f858d4d45-zrmz7     1/1       Running   0          1m

    测试pod alpine

    # kubectl run test --rm -it --image=alpine /bin/sh

    / # cat /etc/resolv.conf
    nameserver 10.68.0.2
    search default.svc.cluster.local. svc.cluster.local. cluster.local.
    options ndots:5

    测试外部域名解析

    / # nslookup www.baidu.com
    Server:    10.68.0.2
    Address 1: 10.68.0.2 kube-dns.kube-system.svc.cluster.local

    Name:      www.baidu.com
    Address 1: 115.239.211.112
    Address 2: 115.239.210.27

    部署集群存储

    在kubernetes(k8s)中对于存储的资源抽象了两个概念,分别是PersistentVolume(PV)、PersistentVolumeClaim(PVC)。

    其中PV是集群中的资源;PVC是对这些资源的请求。而PV又有两种提供方式:静态或动态。这里以NFS存储为例,讲解k8s 众多存储方案中的一个实现。

    静态PV

    首先我们需要一个NFS服务器,用于提供底层存储。这里省略,因为之前我们已经搭建了一个NFS服务。

    创建静态pv,指定容量,访问模式,回收策略,存储类等:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv001
    spec:
      capacity:
        storage: 10Gi
      accessModes:
        - ReadWriteMany         #读写权限,允许被多个Node挂载
      volumeMode: Filesystem
      persistentVolumeReclaimPolicy: Recycle
      storageClassName: "nfs-class-01"
      nfs:
        path: /data/k8s             #指定共享目录
        server: 192.168.30.150              #指定nfs服务器ip

    再创建PVC,自动实现绑定:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: myclaim
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 10Gi

    动态PV

    在一个工作k8s 集群中,PVC请求会很多,如果每次都需要管理员手动去创建对应的PV资源,那就很不方便。因此K8S还提供了多种 provisioner来动态创建PV,不仅节省了管理员的时间,还可以根据StorageClasses封装不同类型的存储供PVC 选用。项目中的role: cluster-storage目前支持自建nfs和aliyun_nas的动态provisioner。

    修改配置文件:

    # vim roles/cluster-storage/defaults/main.yml

    # 动态存储类型, 目前支持自建nfs和aliyun_nas
    storage:
      # nfs server 参数
      nfs:
        enabled: "yes"
        server: "192.168.30.150"
        server_path: "/data/k8s"
        storage_class: "class-nfs-01"
        provisioner_name: "nfs-jenkins-01"

      # aliyun_nas 参数
      aliyun_nas:
        enabled: "no"               # no表示不启用
        server: "xxxxxxxxxxx.cn-hangzhou.nas.aliyuncs.com"
        server_path: "/"
        storage_class: "class-aliyun-nas-01"
        controller_name: "aliyun-nas-controller-01"

    创建nfs provisioner:

    # ansible-playbook /etc/ansible/roles/cluster-storage/cluster-storage.yml

    # kubectl get pod --all-namespaces |grep nfs-jenkins
    kube-system   nfs-jenkins-01-7ffdb44d9d-mvxkk               1/1       Running   0          1h

    验证使用动态PV

    创建测试的PVC:

    # kubectl apply -f /etc/ansible/manifests/storage/test.yaml

    # kubectl get pv
    pvc-00de6ba5-4602-11e9-89a3-000c29d20ca7   1Mi        RWX            Delete           Bound     default/test-claim    class-nfs-01             1h

    # kubectl get pvc
    NAME          STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    test-claim    Bound     pvc-00de6ba5-4602-11e9-89a3-000c29d20ca7   1Mi        RWX            class-nfs-01   1h

    可以发现挂载的时候,nfs-client根据PVC自动创建了一个目录,我们Pod中挂载的/mnt,实际引用的就是该目录,而我们在/mnt下创建的SUCCESS文件,也自动写入到了这个目录下面。

    部署ingress

    ngress就是从外部访问k8s集群的入口,将用户的URL请求转发到不同的service上。ingress相当于nginx反向代理服务器,它包括的规则定义就是URL的路由信息;它的实现需要部署Ingress controller(比如 traefik ingress-nginx 等),Ingress controller通过apiserver监听ingress和service的变化,并根据规则配置负载均衡并提供访问入口,达到服务发现的作用。

    未配置ingress:

    集群外部 → NodePort → K8S Service

    配置ingress:

    集群外部 → Ingress → K8S Service

    • 注意:ingress 本身也需要部署Ingress controller时使用以下几种方式让外部访问
      • 使用NodePort方式
      • 使用hostPort方式
      • 使用LoadBalancer地址方式

    下面就以部署traefik为例。

    部署traefik

    安装traefik ingress-controller:

    # kubectl create -f /etc/ansible/manifests/ingress/traefik/traefik-ingress.yaml

    这里需要注意:

        注意需要配置 RBAC授权

        注意trafik pod中 80端口为 traefik ingress-controller的服务端口,8080端口为 traefik 的管理WEB界面;为后续配置方便指定80 端口暴露NodePort端口为 23456(对应于在hosts配置中NODE_PORT_RANGE范围内可用端口)

        验证traefik ingress-controller:
    # kubectl get deploy -n kube-system traefik-ingress-controller
    NAME                         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    traefik-ingress-controller   1         1         1            1           1d

    # kubectl get svc -n kube-system traefik-ingress-service
    NAME                      TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                       AGE
    traefik-ingress-service   NodePort   10.68.89.151   <none>        80:23456/TCP,8080:27528/TCP   1d

    可以看到traefik-ingress-service 服务端口80暴露的nodePort确实为23456。

    • 测试ingress:

    首先创建测试用K8S应用,并且该应用服务不用nodePort暴露,而是用ingress方式让外部访问。

    # kubectl run test-hello --image=nginx --expose --port=80

    然后为这个应用创建 ingress。

    # kubectl create -f /etc/ansible/manifests/ingress/test-hello.ing.yaml
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: test-hello
    spec:
      rules:
      - host: hello.test.com
        http:
          paths:
          - path: /
            backend:
              serviceName: test-hello
              servicePort: 80

    集群内部尝试访问: curl -H Host:hell.test.com 10.68.89.151(traefik-ingress-service的服务地址) 能够看到欢迎页面 Welcome to nginx!;

    集群外部尝试访问(假定集群一个NodeIP为 192.168.30.130): curl -H Host:hello.test.com 192.168.30.130:23456,也能够看到欢迎页面 Welcome to nginx!,说明ingress测试成功。

        为traefik web管理页面创建 ingress 规则:

    # kubectl create -f /etc/ansible/manifests/ingress/traefik/traefik-ui.ing.yaml

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: traefik-web-ui
      namespace: kube-system
    spec:
      rules:
      - host: traefik-ui.test.com
        http:
          paths:
          - path: /
            backend:
              serviceName: traefik-ingress-service
              servicePort: 8080

    在本机hosts文件中增加一条记录:192.168.30.130 traefik-ui.test.com,即可通过traefik-ui.test.com:23456访问traefik的web管理界面。

    部署ingress-service的负载均衡

    上面的访问已经实现了ingress功能,但是带有端口,这样不方便,我们需要再次做个代理转发来去掉23456端口。

    利用nginx/haproxy等集群,可以做代理转发以去掉23456这个端口。如果你的集群根据本项目部署了高可用方案,那么可以利用LB节点haproxy来做,当然如果生产环境K8S应用已经部署非常多,建议还是使用独立的 nginx/haproxy集群。

        配置负载转发ingress nodeport:

    向集群外暴露ingress-controller本身的服务端口(80/443/8080)一般有以下三种方法:

        部署ingress-controller时使用hostNetwork: true,这样就可以直接使用上述端口,可能与host已listen端口冲突
        部署ingress-controller时使用LoadBalancer类型服务,需要集群支持LoadBalancer
        部署ingress-controller时使用nodePort类型服务,然后在集群外使用 haproxy/f5 等配置 virtual server 集群

    这里以使用 haproxy 配置 ingress的 VS 集群,前提是多主多节点集群并且配置了自建lb节点。

        配置lb参数开启转发ingress nodeport:

    # vim /etc/ansible/roles/lb/defaults/main.yml
    # 启用 ingress NodePort服务的负载均衡 (yes/no)
    INGRESS_NODEPORT_LB: "yes"
    # 启用 ingress tls NodePort服务的负载均衡 (yes/no)          
    INGRESS_TLS_NODEPORT_LB: "no"               #如果不配置https ingress,这里选择no

    重新配置启动LB节点服务:

    # ansible-playbook /etc/ansible/roles/lb/lb.yml

    验证 lb 节点的 haproxy 服务配置:

    # cat /etc/haproxy/haproxy.cfg

    listen kube-master
            bind 0.0.0.0:8443
            mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.51 192.168.1.51:6443 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.52 192.168.1.52:6443 check inter 2000 fall 2 rise 2 weight 1

    listen ingress-node
        bind 0.0.0.0:80
        mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.233 192.168.1.233:23456 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.253 192.168.1.253:23456 check inter 2000 fall 2 rise 2 weight 1

    listen ingress-node-tls
        bind 0.0.0.0:443
        mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.233 192.168.1.233:23457 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.253 192.168.1.253:23457 check inter 2000 fall 2 rise 2 weight 1

    配置文件中有上面的配置就说明配置没问题,其实这一步应该放到部署traefik前面来完成。

    这样我们就直接去掉了23456端口,在hosts文件中加上相应的域名记录,就可以直接通过域名访问到相应的k8s应用了。

    部署jenkins

    之所以部署前面的东西,就是为了部署jenkins,基于k8s部署jenkins可以实现的Jenkins动态Slave CI/CD流程。

    编辑镜像:

    # docker pull jenkins/jenkins:lts

    # docker run -d -p  8090:8080 -p 50000:50000 -v /var/jenkins_home --name jenkins jenkins/jenkins:lts
    941d70ec5d60bff9fa621794c0a2cedcbb8a761d564aa4b32b990166abb92088

    # docker cp jenkins.war jenkins:/usr/share/jenkins/             #准备最新版本的war包,替换

    # docker commit 941d7 jenkins/jenkins:latest

    推送镜像到harbor:

    # docker login harbor.lzxlinux.com

    # docker tag jenkins/jenkins:latest harbor.lzxlinux.com/jenkins/jenkins:latest

    # docker push !$

     修改配置文件:

    # vim /etc/ansible/manifests/jenkins/values.yaml

    Master:
      Name: jenkins-master
      ImagePullSecret: my-secret
      Image: "harbor.lzxlinux.com/jenkins/jenkins"
      ImageTag: "latest"
      ImagePullPolicy: "IfNotPresent"
      Component: "jenkins-master"
      UseSecurity: true
      AdminUser: admin
      AdminPassword: lzxlzx
     
    HostName: jenkins.test.com

        - kubernetes:1.14.8             #相关插件
        - workflow-aggregator:2.6
        - workflow-job:2.26
        - credentials-binding:1.18
        - git:3.9.3
        - gitlab:1.5.11

    Agent:
      Enabled: true
      Image: jenkinsci/jnlp-slave
      ImageTag: alpine
    # ImagePullSecret: jenkins
      Component: "jenkins-slave"
      Privileged: false
        
      StorageClass: "class-nfs-01"              #这里一定要与之前配置的动态PV中的一致,否则报错

    通过helm安装:

    # helm install /etc/ansible/manifests/jenkins/ --name jenkins           #若报错请加上 --tls

    # kubectl get pod
    NAME                       READY     STATUS     RESTARTS   AGE
    jenkins-5cfc5fcd4b-779cs   0/1       Init:0/1   0          2m

    # kubectl describe pod jenkins-5cfc5fcd4b-779cs
      Normal   Pulling           1s               kubelet, 192.168.30.129  pulling image "harbor.lzxlinux.com/jenkins/jenkins:latest"
      Normal   Pulled            <invalid>        kubelet, 192.168.30.129  Successfully pulled image "harbor.lzxlinux.com/jenkins/jenkins:latest"
      Normal   Created           <invalid>        kubelet, 192.168.30.129  Created container
      Normal   Started           <invalid>        kubelet, 192.168.30.129  Started container
      Normal   Pulled            <invalid>        kubelet, 192.168.30.129  Container image "harbor.lzxlinux.com/jenkins/jenkins:latest" already present on machine
      Normal   Created           <invalid>        kubelet, 192.168.30.129  Created container
      Normal   Started           <invalid>        kubelet, 192.168.30.129  Started container
     
    # kubectl get pod
    NAME                       READY     STATUS    RESTARTS   AGE
    jenkins-5cfc5fcd4b-779cs   1/1       Running   0          3m

    # kubectl get svc
    NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
    jenkins         ClusterIP   10.68.174.118   <none>        8080/TCP    3m
    jenkins-agent   ClusterIP   10.68.172.23    <none>        50000/TCP   3m
    kubernetes      ClusterIP   10.68.0.1       <none>        443/TCP     1h

    通过这样的安装方式,可以自动安装配置文件中包含的插件。

    # kubectl logs -f jenkins-5cfc5fcd4b-779cs              #查看启动进度

    如果安装有问题:

    # helm delete --purge jenkins

    可以这样删除,检查配置文件无误后重新安装。

    访问web界面:

    在本地hosts文件中增加一条hosts记录:192.168.30.129 jenkins.test.com,这里ip可以是集群中任一ip。通过域名访问jenkins界面。

    账号:admin,密码:lzxlzx。这是之前在配置文件中设置的。

    新增一个云:

     这一步其实在安装jenkins过程中就已经设置好了,没特殊要求我们可以不做改动。

    只要连接测试成功就说明没有问题。

    新增流水线任务:

    • cloud:插件配置中的Name

    • label:插件配置中的Images → Kubernetes Pod Tempalte → Labels

    • node:与label一致即可

    • 构建:

    点击立即构建,查看控制台输出

     查看pod情况:

    # kubectl get pod
    NAME                       READY     STATUS              RESTARTS   AGE
    default-cxj8q              0/1       ContainerCreating   0          8s
    jenkins-5cfc5fcd4b-779cs   1/1       Running             1          30m

    构建完成

     查看pod情况:

    # kubectl get pod
    NAME                       READY     STATUS              RESTARTS   AGE
    default-cxj8q              0/1       Terminating         0          1m
    jenkins-5cfc5fcd4b-779cs   1/1       Running             1          30m

    # kubectl get pod
    NAME                       READY     STATUS              RESTARTS   AGE
    jenkins-5cfc5fcd4b-779cs   1/1       Running             1          30m

    可以看到pod副本是根据任务构建来动态创建和终止的,这就实现了K8s集群Jenkins 动态Slave CI/CD流程。

    更多参考资料:

    https://blog.csdn.net/qq_34605594/article/details/79241373

    https://blog.csdn.net/qq_34605594/article/details/79258596

  • 相关阅读:
    IBinder介绍
    Android组成部分
    Android中handler,looper与messageQueue的代码解析
    JS
    设计模式
    冒泡排序
    战斗逻辑
    mongo数据库基础
    JS闭包
    c/c++
  • 原文地址:https://www.cnblogs.com/qq3245792286/p/16205831.html
Copyright © 2020-2023  润新知