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技术爱好者
  • 相关阅读:
    SharePoint 2010 User Profile Sync Service自动停止
    如何区别多个svchost.exe?
    Log Parser分析IIS log的一个简单例子
    Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
    Windows中右键点击文件夹, 结果找不到共享选项卡, 怎么办?
    介绍SOS中的SaveModule命令
    SharePoint中Draft版本的文档不会收到document added的Alert Email
    和我一起学Windows Workflow Foundation(1)创建和调试一个WF实例
    门户网站
    C#基础—— check、lock、using语句归纳
  • 原文地址:https://www.cnblogs.com/majiang/p/14461687.html
Copyright © 2011-2022 走看看