zoukankan      html  css  js  c++  java
  • jenkins自动化部署go【docker+jenkins+go+gitlab+harbor+k8s】

    首先说一下我的环境,首先准备一台ubuntu18.4虚拟机,安装docker, 然后用docker 安装gitlab[大家可以参考 Ubuntu Docker搭建GitLab以及常规配置使用]  和harbor【大家可以参考 Ubuntu18 安装搭建Harbor】,关于k8s的安装大家 可以参考 Ubuntu 18 Kubernetes集群的安装和部署 以及Helm的安装Centos 使用kubeadm安装Kubernetes 1.15.3 关于harbor 程序手动更新到k8s 参考 Windows docker k8s asp.net core.我尝试过通过docker来安装jenkins,jenkins容器里面在安装docker和harbor通信,但是后面还是遇到很多问题 不好解决, docker默认是无状态的 需要保存的数据都要挂在的虚拟机上, 比如jenkins里面下载的golang镜像,jenkins重启就丢失了, 所以后面彩用jenkins直接安装到虚拟机上。

    jenkins安装

    #准备工作
    #存储库密钥添加到系统
    wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
    #将Debian包存储库地址附加到服务器的sources.list
    echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list
    
    apt-get update
    sudo apt-get install -y openjdk-8-jdk
    sudo apt-get install -y jenkins
    
    #如果你的端口8080被占用
    #编辑`/etc/default/jenkins`, 修改 ----HTTP_PORT=8080----`为----HTTP_PORT=8081----` 在这里,“8081”也可被换为其他可用端口
    
    #启动Jenkins
    sudo systemctl start jenkins
    sudo systemctl status jenkins

    jenkins的配置我们就省略了, 部署项目我们时 在开发测试环境可以直接在jenkins上直接运行docker实例,也可以把docker推到harbor上,至于harbor到k8s上后面在写一篇文章。

    go项目

    为了省事我们把必要脚本都放到项目里面,项目结构如下:

     我们的Dockerfile文件如下:

    FROM golang:1.15.6

    RUN mkdir -p /app
    RUN mkdir -p /app/conf
    RUN mkdir -p /app/logs

    WORKDIR /app
     
    ADD main /app/main

    EXPOSE 8080
     
    CMD ["./main"]

    build.sh文件是把docker镜像推到harbor上的【已经测试通过】

    #!/bin/bash
    #cd $WORKSPACE
    
    export GOPROXY=https://goproxy.io
     
     #根据 go.mod 文件来处理依赖关系。
    go mod tidy
    
    # linux环境编译
    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main
    
    # 构建docker镜像,项目中需要在当前目录下有dockerfile,否则构建失败
    
    docker build -t gavintest .
    docker tag  gavintest 192.168.100.30:8080/go/gavintest:${BUILD_NUMBER}
    
    docker push 192.168.100.30:8080/go/gavintest
    
    docker rmi  gavintest
    docker rmi 192.168.100.30:8080/go/gavintest:${BUILD_NUMBER}
    
    cd ..
    #删除项目文件夹
    rm -rf gavintest

    buildtest.sh是在jenkins上直接运行docker实例

    #!/bin/bash
    #cd $WORKSPACE

    export GOPROXY=https://goproxy.io
     
     #根据 go.mod 文件来处理依赖关系。
    go mod tidy

    # linux环境编译
    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main

    #删除docker
    docker stop gavintest
    docker rm gavintest
    docker rmi  gavintest

    # 构建docker镜像,项目中需要在当前目录下有dockerfile,否则构建失败
    docker build -t gavintest .

    mkdir logs
    mkdir conf2
    #挂载资源文件夹 运行docker
    docker run -d --name gavintest   -p 9999:8080 -v $(pwd)/conf:/app/conf -v $(pwd)/logs:/app/logs  gavintest

    在jenkins上创建一个 自由风的项目 gavintest, 调用shell脚本:

    cd /var/lib/jenkins/workspace/gavintest
    chmod 777 buildtest.sh
    ./buildtest.sh

     jenkins构建结果:

    访问结果:

     修改配置

     重启docker restart gavintest然后访问

    k8s部署

    准备【手动部署一次】

    这里需要用到pvc,关于pvc的搭建我就省略了, 大家可以参考 ubuntu kubernetes中使用NFS创建pv_pvc  ,以下都是在k8s master上执行,[我为了方便把 端口改为80了而不在是8080]

    命令空间1.准备namespace.yaml

    apiVersion: v1
    kind: Namespace
    metadata:
       name: go
       labels:
         name: go
    kubectl apply -f namespace.yaml
    #因为是私有的harbor所以需要创建regsecret认证,然后在deploy文件引用它
    kubectl create secret docker-registry regsecret --docker-server=192.168.100.30:8080 --docker-username=admin --docker-password=123456 -n=go
    #kubectl delete secret regsecret  -n=go

    创建mypv.yaml (kubectl apply -f mypvc.yaml)

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv001
    spec:
      capacity:
        storage: 100M
      accessModes:
        - ReadWriteMany
      nfs:
        path: /data/k8s/
        server: 192.168.100.11

    和mypvc.yaml (kubectl apply -f mypvc.yaml)

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

    和deploy.yaml (kubectl apply -f deploy.yaml)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gavintest
      namespace: go
    spec:
      replicas: 5
      minReadySeconds: 10 
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
      selector:
        matchLabels:
          name: gavintest
      template:
        metadata:
          labels:
            name: gavintest
        spec:
          imagePullSecrets:
          - name: regsecret
          containers:
          - name: gavintest
            image: 192.168.100.30:8080/go/gavintest:20210301
            ports:
            - containerPort: 80
            imagePullPolicy: Always
            volumeMounts:
             - mountPath: "/app/conf"
               name: httpd-volume
          volumes:
          - name: httpd-volume
            persistentVolumeClaim:
              claimName: myclaim

    我们可以用kubectl exec -it  podnamexxx   -n gobash 进入pod验证以下

     或者  kubectl get pod -o wide -n go 查看ip直接访问

     service.ymal  (kubectl apply -f service.ymal)

    apiVersion: v1 
    kind: Service 
    metadata:
      name: gavintest
      namespace: go 
    spec:
      type: ClusterIP
      ports:
        - port: 80 
          targetPort: 80 
          protocol: TCP 
      selector:
        name: gavintest

     ingress.yaml  (kubectl apply -f ingress.yaml )  可以参考 https://www.cnblogs.com/fanqisoft/p/11609172.html

    apiVersion: extensions/v1beta1 
    kind: Ingress 
    metadata:
      name: gavintest
      namespace: go
    spec:
      rules:
        - host: k8s.go.com
          http:
            paths: 
              - path: /  
                backend:
                  serviceName: gavintest
                  servicePort: 80

     配置域名host 然后访问:

     手动部署结果成功:

    修改配置文件 然后手动重启 以下pod 看看配置是否更新

    #pod 重启方法1
    kubectl scale deployment XXXX --replicas=0 -n {namespace}
    kubectl scale deployment XXXX --replicas=1 -n {namespace}
    
    #方法2
    kubectl delete pod {podname} -n {namespace}
    
    #方法3
    kubectl get pod {podname} -n {namespace} -o yaml | kubectl replace --force -f -
    
    #方法4Kubernetes 1.15开始才有
    #kubectl rollout restart deploy {your_deployment_name}
    kubectl rollout restart deploy gavintest -n go

    推送到harbor的效果图:

     现在我们搞一个rollout.sh文件【需要和gavintest_dm.yaml同级目录】, 就是根据现有的deploy.yaml文件来生成新的部署文件,然后调用/data/k8s/rollout.sh 38 [38是harbor里面镜像版本号,如果有权限问题
    chmod 777 /data/k8s/rollout.sh]

    #!/bin/bash
    workdir="/data/k8s"
    project="gavintest"
    job_number=$(date +%s)
    cd ${workdir}
    oldversion=$(cat ${project}_dm.yaml | grep "image:" | awk -F ':' '{print $NF}')
    newversion=$1
    
    echo "old version is: "${oldversion}
    echo "new version is: "${newversion}
    
    sed -i.bak${job_number} 's/'"${oldversion}"'/'"${newversion}"'/g' ${project}_dm.yaml
    
    kubectl apply -f ${project}_dm.yaml --record=true

     

    那么jenkins就可以用过ssh 192.168.100.11 "cd /data/k8s   && sh rollout.sh ${BUILD_NUMBER}"  来调用shell了

    错误Host key verification failed 的解决

    a.jenkins普通用户无法执行某些系统命令;

    b.我们并没有为jenkins生成过密钥对,也没有将他的公钥拷到目标服务器上.

      在安装jenkins后,系统生成了jenkins这个普通用户,但是在/etc/passwd中,他的shell是/bin/false,所以他不能登录系统,也没有家目录;

      首先我们修改他的登录权限,将/bin/false改为/bin/bash,切换到jenkins用户,su - jenkins,他的终端显示为-bash-4.2$,修改终端显示.

    终端修改完之后长这个样子

    生成密钥对

    具体步骤

    vim ~/.bash_profile
    export PS1='[u@h W]$'
    source ~/.bash_profile
    # 给jenkins生成密钥对
    ssh-keygen -t rsa
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.41
    # 验证
    ssh 'root@10.0.0.41'

    3.使用sudo提升普通用户权限

      此时是完成了第二步,但还没有操作第一步,在文件末尾添加一行,就这么一行就有很多要注意的地方,首先修改文件权限为600,然后用viduso去修改文件,中间的空隙不是空格,而是tab,命令和命令之间要用逗号,保存退出后,将权限改为440,而不是400,最后用visudo -c检查语法是否出错.

    jenkins        ALL=(ALL)    NOPASSWD: /usr/bin/ssh, /usr/bin/rsync

    jenkins        ALL=(ALL)    NOPASSWD: ALL

    这两行内容任意选一个都行.

    需要确保k8s master 的vi /etc/ssh/sshd_config 配置

    重启 sudo systemctl restart jenkins,至于如何带哦用远程的sh我这里比较偷懒 直接用插件SSH remote hosts

     

     

     

    注意事项

    1.jenkins账号运行docker 没有权限提示 :dial unix /var/run/docker.sock: connect: permission denied 解决办法

    sudo groupadd docker #添加docker用户组
    sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中
    docker ps #测试当前用户是否可以正常使用docker命令
    
    #把jenkins添加到docker的group里就可以了。
    sudo usermod -a -G docker jenkins
    
    #重启jenkins。
    systemctl restart jenkins

    2.jenkins在王harbor上推送失败,提示push: unauthorized to access repository,解决办法

     #首先登陆harbor
    docker login 192.168.100.30:8080
    
    查看.docker/config.json 文件
    root@server:~#  cat .docker/config.json 
    {
        "auths": {
            "192.168.100.30:8080": {
                "auth": "Z2F2aW46R2F2aW4xMjM="
            }
        },
        "HttpHeaders": {
            "User-Agent": "Docker-Client/19.03.6 (linux)"
        }
    }
    
    #把.docker复制到/var/lib/jenkins目录下
     cp -r .docker/ /var/lib/jenkins/
    修改文件夹权限 chown -R jenkins.jenkins .docker
     cd /var/lib/jenkins/
     chown -R jenkins.jenkins .docker
    systemctl restart jenkins

     3

    1.pod若处于运行状态,则通过kubectl logs 即可
    
    # 查看指定pod的日志
    kubectl logs <pod_name>
    kubectl logs -f <pod_name> #类似tail -f的方式查看(tail -f 实时查看日志文件 tail -f 日志文件log)
    
    # 查看指定pod中指定容器的日志
    kubectl logs <pod_name> -c <container_name>
    
    kubectl logs pod_name -c container_name -n namespace (一次性查看)
    kubectl logs -f <pod_name> -n namespace (tail -f方式实时查看)
    2.若pod处于init状态,则需要通过docker ps查看
    
    #获取对应的pod name
    kubectl get pods -n  namespace -o wide (STATUS是init的pod_name)
    
    #通过docker ps 获取该pod的中的CONTAINER ID
    docker ps | grep pod_name
    
    #通过docker log获取对应的日志信息
    docker logs CONTAINER_ID

    main.go

    package main
    
    import (
        _ "demo/routers"
    
        "github.com/astaxie/beego"
        "github.com/astaxie/beego/logs"
    )
    
    func main() {
    
        _ = logs.SetLogger(logs.AdapterFile, `{"filename":"logs/gavintest.log", "level":7, "daily":true, "maxdays":10}`)
        logs.Debug("website=%v", beego.AppConfig.String("website"))
    
        beego.Run()
    
    }

    default.go

    package controllers
    
    import (
        "github.com/astaxie/beego"
        "github.com/astaxie/beego/logs"
    )
    
    type MainController struct {
        beego.Controller
    }
    
    type responseData struct {
        Data interface{}
        Code int
        Msg  string
    }
    
    func (c *MainController) Get() {
        website := beego.AppConfig.String("website")
        logs.Info("/get:website=%v", website)
    
        ret := &responseData{
            Data: website,
            Code: 200,
            Msg:  "OK",
        }
    
        c.Data["json"] = ret
        c.ServeJSON()
        c.StopRun()
    }
    windows技术爱好者
  • 相关阅读:
    c++中sort等算法中比较操作的规则
    数据结构(c++)(1)-- 栈
    Problem 10: Summation of primes
    Problem 9: Special Pythagorean triplet
    Problem 7: 10001st prime
    Problem 8: Largest product in a series
    Problem 5: Smallest multiple
    Problem 6: Sum square difference
    Problem 4: Largest palindrome product
    Problem 3: Largest prime factor
  • 原文地址:https://www.cnblogs.com/majiang/p/14461687.html
Copyright © 2011-2022 走看看