部署一套新環境,實踐用jenkins實現CD

前提,已經有開發環境,但是因爲開發環境更新很頻繁,會影響到測試,於是準備新建一個sit環境。
前置條件:
已經有一臺jenkins服務器,有新建jenkins用戶,ip爲172.31.17.89.
新開一臺linux虛擬機,安裝好docker,ip爲172.31.17.55.

1、在55上新建一個普通用戶,開通sudo權限
新建用戶 useradd ttop.sit ,再使用passwd 修改密碼。可參考之前的文章
開通sudo權限,編輯/etc/sudoers,加入NOPASSWD:ALL。Linux給普通用戶sudo權限

2、登錄到89這臺機,切換到jenkins用戶,能使用剛新建的用戶 免密登錄到55那臺機
使用ssh-keygen 生成一個密鑰對
再使用ssh-copy-id [USER_NAME]@IP將公鑰發到55那臺機器上,再使用ssh [email protected]發現不再需要輸入密碼。

#確認89機器的jenkins用戶ssh免密登錄至55那臺機,且能使用sudo命令
bash-4.2$ ssh [email protected]
Last failed login: Tue Jun 16 16:06:03 CST 2020 from 172.31.17.89 on ssh:notty
There were 4 failed login attempts since the last successful login.
Last login: Tue Jun 16 14:46:33 2020
[ttop.sit@sit-jm-vcsms ~]$ sudo docker ps
CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS              PORTS                                                                NAMES
7e1400f61dda        repo.ttooc.xyz/jm/ms_file:036745cf   "sh -c 'chmod +x /en…"   3 hours ago         Up 21 seconds       5701/udp, 8080/tcp                                                   jm_file_1
01790ca91b0f        nginx                                "/docker-entrypoint.…"   3 hours ago         Up 3 hours          0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8761->8761/tcp   nginx

3、運行registry容器

docker run \
-e SPRING_PROFILES_ACTIVE=dev,composite,swagger,peer1,zipkin,no-liquibase \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE=git \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_URI="https://devops.ttotox.net/XXXXXXXX/_git/profile-sit(存放配置文件的git庫地址)" \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH-PATHS="/"  \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_USERNAME=cicd.xxxx (能查看git庫的用戶) \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_PASSWORD=xxxxxxx (密碼) \
-e JHIPSTER_CORS_ALLOWED-ORIGINS="*" \
-e JHIPSTER_CORS_ALLOWED-METHODS="*" \
-e JHIPSTER_CORS_ALLOWED-HEADERS="*" \
-e JHIPSTER_CORS_EXPOSED-HEADERS="Authorization,Link,X-Total-Count" \
-e JHIPSTER_CORS_ALLOWED-CREDENTIALS=true \
-e JHIPSTER_CORS_MAX-AGE=1800 \
-e ENCRYPT_KEY=jmvcsmscryptkeysit \
-e EUREKA_CLIENT_SERVICE-URL_DEFAULTZONE=http://admin:admin@eureka-peer-2:8762/eureka/  \
-v /etc/localtime:/etc/localtime \
--network jm \
--ip 172.20.0.100 \
--add-host eureka-peer-1:172.20.0.100 \
--add-host eureka-peer-2:172.20.0.101 \
--add-host localhost:127.0.0.1 \
--restart=always \
-itd --name jm_registry_sit_peer1 \
jhipster/jhipster-registry:v6.2.0

docker run \
-e SPRING_PROFILES_ACTIVE=dev,composite,swagger,peer2,zipkin,no-liquibase  \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE=git \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_URI="https://devops.ttotox.net/XXXXXXXX/_git/profile-sit" \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH-PATHS="/"  \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_USERNAME=cicd.xxx  \
-e SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_PASSWORD=xxxxxx  \
-e JHIPSTER_CORS_ALLOWED-ORIGINS="*" \
-e JHIPSTER_CORS_ALLOWED-METHODS="*" \
-e JHIPSTER_CORS_ALLOWED-HEADERS="*" \
-e JHIPSTER_CORS_EXPOSED-HEADERS="Authorization,Link,X-Total-Count" \
-e JHIPSTER_CORS_ALLOWED-CREDENTIALS=true \
-e JHIPSTER_CORS_MAX-AGE=1800 \
-e ENCRYPT_KEY=jmvcsmscryptkeysit \
-e EUREKA_CLIENT_SERVICE-URL_DEFAULTZONE=http://admin:admin@eureka-peer-1:8761/eureka/  \
-v /etc/localtime:/etc/localtime \
--network jm \
--ip 172.20.0.101 \
--add-host eureka-peer-1:172.20.0.100 \
--add-host eureka-peer-2:172.20.0.101 \
--add-host localhost:127.0.0.1 \
--restart=always \
-itd --name jm_registry_sit_peer2 \
jhipster/jhipster-registry:v6.2.0


SPRING_PROFILES_ACTIVE 此變量prod,composite,swagger,peer1,zipkin,no-liquibase

prod或者dev是registry自帶有兩個配置文檔,如果想自定義uat則在項目下新建uat的配置文檔即可,使用prod則說明優先讀prod的配置
composite,peer1此爲組合使用,涉及到eureka註冊地址
swagger,開啓swagger查看api zipkin,監控相關
no-liquibase,不使用liquibase記錄數據庫表結構變更

上面起了兩個registry後,接下來就是新建jenkins流水線,因爲CI之前已經弄好了,這裏只需要弄好CD即可。

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
流水線新建完成,這裏的git庫用戶憑據是之前就生成了的,若沒有,可自己新建一個。jenkins->憑據->系統->全局憑據->新建憑據
在這裏插入圖片描述
再查看一下git庫下的dev_cd_sit中的腳本。總的來說就是給個微服務的名稱,然後給個鏡像的版本號,就可以自動部署起來。裏面還有一個參數sshId,這是一個遠程的憑據,是從jenkins服務器連到要部署微服務的那臺服務器,也就是89到55,再看下面的腳本用的是 sshUserPrivateKey,說明這是一個PrivateKey憑據,貌似之前的免密白搞了,於是再生成一個私鑰憑證。

pipeline {
	agent any
	parameters {
        string(name: 'MS_NAME', defaultValue: '', description: '微服務名稱')
		string(name: 'COMMIT_ID', defaultValue: '', description: 'COMMIT_ID')
    }
    environment {
        PATH = "$PATH"
		remote="172.31.17.55"
		serverName="${params.MS_NAME}"
		container="jm_${serverName}_1"
		dockerRegistryUser="impos"
		dockerRegistryPassword="impos"
		dockerRegistry="repo.ttoocx.xyz"
        dockerTag="${dockerRegistry}/jm/ms_${serverName}"
		sshId="301a3c42-657d-4a2c-a003-e220466xxxxx"
		dockerJavaOpts="-Xmx800M"
		dockerRunParams=""
    }	
    stages {
        stage("Initialization") {
            steps {
                // use name of the patchset as the build name
                buildName "#${BUILD_NUMBER}-${serverName}-${params.COMMIT_ID}"
                buildDescription "${serverName}"
            }
        }		
        stage('通過SSH發佈到DEV') {
            steps {
				script{
					withCredentials([sshUserPrivateKey(credentialsId: "${sshId}", keyFileVariable: 'PRIVATEKEYFILE', passphraseVariable: '', usernameVariable: 'USERNAME')]) {			
						script{
							try {
								sh "ssh -o \"StrictHostKeyChecking no\" ${USERNAME}@${remote} -i ${PRIVATEKEYFILE} sudo docker rm -f ${container}"
								sh "ssh -o \"StrictHostKeyChecking no\" ${USERNAME}@${remote} -i ${PRIVATEKEYFILE} sudo docker system prune -a -f"
							}
							catch(error){
								echo "停止舊容器發生錯誤,可能是已經被刪除,跳過"
							}
						}		
						sleep 5
						def dockerRunParams=""	
						if (params.MS_NAME == 'gateway') {
							dockerRunParams="--ip 172.20.0.102";
						}						
						if (params.MS_NAME == 'file') {
							dockerRunParams="-v /opt/jm/files:/files:Z";
						}
						if (params.MS_NAME == 'websocket') {
							dockerRunParams="-p 2222:8081";
						}		
						if(params.MS_NAME=='wechat'){
							dockerRunParams = "-v /opt/jm/wechat/apiclient_cert.p12:/wechat/cert.p12";
						}
						sh "ssh -o \"StrictHostKeyChecking no\" ${USERNAME}@${remote} -i ${PRIVATEKEYFILE} sudo docker login -p ${dockerRegistryUser} -u ${dockerRegistryPassword} ${dockerRegistry}"
						sh "ssh -o \"StrictHostKeyChecking no\" ${USERNAME}@${remote} -i ${PRIVATEKEYFILE} sudo docker run ${dockerRunParams} -e EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:admin@eureka-peer-1:8761/eureka,http://admin:admin@eureka-peer-2:8762/eureka -e SPRING_CLOUD_CONFIG_URI=http://admin:admin@eureka-peer-1:8761/config,http://admin:admin@eureka-peer-2:8762/config -e JHIPSTER_REGISTRY_PASSWORD=admin -e SPRING_PROFILES_ACTIVE=dev,composite,swagger,zipkin,no-liquibase -e JAVA_OPTS=\"${dockerJavaOpts}\" --network jm --add-host eureka-peer-1:172.20.0.100 --add-host eureka-peer-2:172.20.0.101 --restart=always --name ${container} -itd ${dockerTag}:${params.COMMIT_ID}"
						
					}	
				}			
            }
        }			
    }
}

生成私鑰憑證
在這裏插入圖片描述
在這裏插入圖片描述
仔細思考一下,如果89要連到55去操作,而之前免密的時候就已經把公鑰發到了55這臺服務器,那麼jenkins(89)想要操作55,是不是隻需要把與那個公鑰配對的那個私鑰配到這個憑證裏,之後就可以登錄55那臺機操作了?

登錄89,找到私鑰,一開始進到jenkins用戶,發現沒有.ssh目錄,於是再運行ssh-keygen看它保存的路徑在哪裏。在此路徑下找到id_rsa文件,把裏面的內容配到憑證 私鑰位置。注意整個放進去,不要去掉開頭和結尾的----
在這裏插入圖片描述
保存憑據,拿到id,配置到腳本的sshId處。

運行流水線,看是否能成功啓動容器,以及容器是否註冊進registry。
遇到的問題:
1、一開始憑據使用的是用戶名密碼,運行流水線後,報錯ERROR: Credentials ‘f27ebc14-a76e-4d13-8990-701b7acda412’ is of type ‘Username with password’ where ‘com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey’ was expected
查看腳本後,發現使用的是SSHUserPrivateKey,而我使用的憑據是用戶名密碼的,於是更換憑據,得到解決。

2、私鑰憑證,一開始有些換亂,不知道是要哪個私鑰,後來仔細思考,這個憑證到底是幹啥用的?
看腳本是要ssh連接到55那臺機使用的,那如何才能ssh連接到服務器?之前學習的時候有了解到可以使用用戶密碼以及公鑰私鑰登錄,但是具體的原理沒有深入去理解,ssh-kengen這是生成一個密鑰對,一個公鑰一個私鑰,ssh-copy-id其實是把公鑰放到服務器,那爲什麼這樣就可以遠程?客戶端拿着私鑰去到服務器,服務器中的公鑰可以與之配對,於是得以通過認證,連接到服務器。那麼如果jenkins要連接到服務器,也就是隻要拿着與之匹配的私鑰過去即可,於是想到拿jenkins生成的那條私鑰,配上,成功。

3、容器運行起來後,發現沒有註冊進registry,檢查腳本後,發現是參數SPRING_PROFILES_ACTIVE ,啓動registry與CD腳本中啓動容器的值不一致,修改爲一致的之後得到解決。

4、之前是直接暴露registry容器地址,以此訪問registry後臺,但是這次的腳本中發現沒有暴露registry的端口,而開發環境中確實可以通過該端口訪問registry的,查看之後發現加了一層,用了nginx來轉發,把nginx運行起來,通過nginx來暴露registry的端口,給到外部訪問,該問題得到解決。
啓動nginx的命令及配置文件如下:

sudo docker run --privileged=true -v /opt/jm/nginx/:/etc/nginx/conf.d/:ro -p 80:80 -p 8761:8761 -p 8080:8080 --network jm --restart=always --name nginx -d nginx

查看掛載的/opt/jm/nginx文件目錄下有兩個文件,一個是default.conf和registry.conf
default.conf文件內容如下
upstream gateway {
    server 172.20.0.102:8080; #查看之前CD腳本,這是gateway的ip
}
server {
    listen       80;
    listen  8080;
    server_name  localhost;

    #charset koi8-r;
    access_log  /var/log/nginx/host.access.log  main;
    error_log   /var/log/nginx/error.default.log    error;
    location / {
        proxy_pass http://gateway;
        proxy_http_version 1.1;
        proxy_buffer_size  128k;
        proxy_buffers   32 256k;
        proxy_busy_buffers_size 256k;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /html {
        root   /usr/share/nginx;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}


registry.conf文件內容如下

upstream registry {
    server 172.20.0.100:8761;
    server 172.20.0.101:8762;
}

server {
    listen       8761;
    server_name  localhost;

    location / {
  
        proxy_pass http://registry;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章