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()
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM