運用Docker+Jenkins+Nginx+Spring Boot 自動化部署項目


1 Docker+Jenkins+Nginx+Spring Boot 自動化部署項目

Docker通過linux的namespace實現資源隔離、cgroups實現資源控制,通過寫時復制機制(copy-on-write)實現了高效的文件操作,在實際開發中可用於提供一次性的環境、微服務架構的搭建、統一環境的部署。

雖然Docker已經是風靡全球的容器技術了,統一環境避免環境問題上是Docker的主要吸引點之一,但使用時詳細還是會遇到不少問題的,比如個人搭建時曾思考過這些問題:

Jenkins官網既然有Docker上安裝Jenkins的流程了,那我該怎么使用Jenkins容器呢?

如果使用Jenkins容器,我該怎么通過Jenkins容器部署SpringBoot項目?是通過Jenkins容器與SpringBoot容器中的文件交互進行項目部署嗎?這能做到嗎?又或是把SpringBoot項目放到Jenkins容器中管理,那Jenkins中又要安裝git、maven等一堆東西,這一點都不方便。

使用IDEA Docker插件都可以直接本地連接到服務器的Docker創建鏡像並運行容器了,為什么還需要Jenkins?

個人在實際搭建部署中也找到了與上相對應的答案:

如果使用Jenkins容器,這將使得部署更加麻煩,因Jenkins往往需要配置Maven、git等一系列變量,應另尋出路。

Jenkins既然是一款腳本CI工具,而Docker也有自己的腳本,我應該將Docker腳本集成到Docker中這方面考慮。

在實際開發中,Jenkins可能不僅需要項目的部署,還需要進行開發人員的鑒權,如開發人員A只能查看部署指定項目,管理員可以查看部署所有項目,但Docker主要用於鏡像構建與容器運行,無法像Jenkins一樣獲取github/gitlab代碼,也無法進行開發人員的鑒權,所以Docker可以在Jenkins中只扮演簡化部署過程的一個角色。

雖然IDEA插件可以直接把本地打包成功的項目部署服務器Dcoker並創建鏡像運行容器,但為了安全還需要創建Docker CA認證下載到本地再進行服務器上的Docker連接,十分不便捷。

當探索到自我提問的答案時,便確定了各組件的主要職責:

Jenkins:接收項目更新信息並進行項目打包與Docker腳本的執行

Docker:安裝所需應用鏡像與運行容器

git:項目信息同步

搭建環境流程:

  1. 安裝JDK
  2. 安裝Maven
  3. 安裝git
  4. 安裝Jenkins(該步驟之前的可參考Jenkins安裝並部署Java項目完整流程)如有權限問題可將/etc/sysconfig/jenkins文件JENKINS_USER修改為root或手動賦權
  5. Centos安裝Docker

   6.安裝DockerCompose

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose --version

使用DockerCompose可省去容器增多時需多次執行docker run的麻煩 

配置文件

1. SpringBoot項目Dockerfile

FROM java:8
MAINTAINER Wilson

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

#這里的 /tmp 目錄就會在運行時自動掛載為匿名卷,任何向 /tmp 中寫入的信息都不會記錄進容器存儲層
VOLUME /ecs-application-docker
RUN mkdir /app
WORKDIR /app

#復制target/spring-boot-web-demo.jar到容器里WORKDIR下
COPY target/ecs-application.jar ecs-application.jar
EXPOSE 9090

ENTRYPOINT ["java","-jar","ecs-application.jar"]

2. 配置docker-compose.yml

version: '3.7'
services:
  app:
    restart: always
    build: ./
    hostname: docker-spring-boot
    container_name: docker-spring-boot
    image: docker-spring-boot/latest
  # 不對外開放端口,只能通過容器訪問
# ports:
# - 8080:8080
    volumes:
      - ./volumes/app:/app
  nginx:
    depends_on:
      - app
    container_name: docker-nginx
    hostname: docker-nginx
    image: nginx:1.17.6
    environment:
      TZ: Asia/Shanghai
    restart: always
    expose:
      - 80
    ports:
      - 80:80
    links:
      - app
    volumes:
      - ./volumes/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./volumes/nginx/conf.d:/etc/nginx/conf.d
      - ./volumes/nginx/logs:/var/log/nginx

3. Nginx

./volumes/nginx/nginx.conf

user nginx;
worker_processes 2; #設置值和CPU核心數一致
error_log /etc/nginx/error.log crit; #日志位置和日志級別
pid /etc/nginx/nginx.pid;
events
{
  use epoll;
  worker_connections 65535;
}
http{
    include mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" "$http_cookie"';

access_log /var/log/nginx/access.log main;
    #charset utf8;

server_names_hash_bucket_size 128;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 8m;

sendfile on;
    tcp_nopush on;
    keepalive_timeout 60;
    tcp_nodelay on;
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml;
    gzip_vary on;

#limit_zone crawler $binary_remote_addr 10m;
    #server虛擬主機的配置
    include /etc/nginx/conf.d/*.conf;

}

./volumes/nginx/conf.d目錄下的default.conf

upstream application {
   server docker-spring-boot:8080;
}
server{
  listen 80;#監聽端口
  server_name localhost;#域名
  access_log /var/log/nginx/nginx-spring-boot.log;
  location / {
      proxy_pass http://application;
      proxy_set_header Host $host:$server_port;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header REMOTE-HOST $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Jenkins部署執行流程

maven打包Spring Boot項目為project.jar,根據是否以第一次項目部署執行以下不同的流程:

如當前掛載卷已含項目jar(即非第一次運行),則運行以下步驟:拷貝project.jar覆蓋掛載卷中的project.jar重新運行SpringBoot項目容器

如當前掛載卷不含項目jar(即非第一次運行),則運行以下步驟:創建掛載卷目錄拷貝project.jar到掛載卷中通過docker-compose讀取docker-compose.yml配置創建鏡像啟動容器

Jenkins腳本(如果Nginx配置更改較多也可添加Nginx容器重啟指令):

cd /var/lib/jenkins/workspace/docker-spring-boot/spring-boot-nginx-docker-demo
mvn clean package
if [ -e "./volumes/app/docker-spring-boot.jar" ]
 then rm -f ./volumes/app/docker-spring-boot.jar \
&& cp ./target/docker-spring-boot.jar ./volumes/app/docker-spring-boot.jar \
&& docker restart docker-spring-boot \
 && echo "update restart success"
else mkdir volumes/app -p \
&& cp ./target/docker-spring-boot.jar ./volumes/app/docker-spring-boot.jar \
&& docker-compose -p docker-spring-boot up -d \
&& echo "first start"
fi

docker-compose up指令可以進行鏡像的安裝,所以也省去了只用docker指令時需要提前准備好鏡像相關指令的麻煩。

查看容器是否皆已啟動:docker ps

 

 SpringBoot容器運行結果查看:

如容器開放了8080端口則可通過http://url:8080/swagger-ui.html測試,也可通過查看Jenkins工作空間下/volumes/app的SpringBoot日志校驗結果(SpringBoot日志的路徑配置個人設置為app/logs目錄下,前文已把容器中的app目錄掛載到當前項目的volumes/app目錄下)

 

 Nginx容器運行結果查看:

訪問http://url/swagger-ui.html測試是否Nginx容器已成功連通SpringBoot容器並進行了反向代理,也可通過查看Jenkins工作空間下/volumes/nginx/logs的Nginx日志校驗結果

 

 添加或刪除controller接口再進行推到git,查看更改的接口是否可訪問

如需將SpringBoot通過容器集群搭建,只需進行以下更改:

docker-compose.yml添加SpringBoot項目冗余,更改冗余容器名,區分日志掛載路徑,冗余項目更改容器名

version: '3.7'
services:
  app:
    restart: always
    build: ./
    hostname: docker-spring-boot
    container_name: docker-spring-boot
    image: docker-spring-boot/latest
    volumes:
      - ./volumes/app/docker-spring-boot.jar:/app/docker-spring-boot.jar
      - ./volumes/app/logs:/app/logs
  app-bak:
    restart: always
    build: ./
    hostname: docker-spring-boot
    container_name: docker-spring-boot-bak
    image: docker-spring-boot/latest
    volumes:
      - ./volumes/app/docker-spring-boot.jar:/app/docker-spring-boot.jar
      - ./volumes/app/logs-bak:/app/logs
  nginx:
    depends_on:
      - app
    container_name: docker-nginx
    hostname: docker-nginx
    image: nginx:1.17.6
    environment:
      TZ: Asia/Shanghai
    restart: always
    expose:
      - 80
    ports:
      - 80:80
    links:
      - app
      - app-bak
    volumes:
      - ./volumes/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./volumes/nginx/conf.d:/etc/nginx/conf.d
      - ./volumes/nginx/logs:/var/log/nginx
nginx更改default.conf的upstream,添加冗余容器配置
upstream application {
   server docker-spring-boot:8080 fail_timeout=2s max_fails=2 weight=1;
   server docker-spring-boot-bak:8080 fail_timeout=2s max_fails=2 weight=1;
}
server{
  listen 80;#監聽端口
  server_name localhost;#域名
  access_log /var/log/nginx/nginx-spring-boot.log;
  location / {
      proxy_pass http://application;
      proxy_connect_timeout 2s;
      proxy_set_header Host $host:$server_port;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header REMOTE-HOST $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Jenkins添加冗余容器重啟腳本
BUILD_ID=DONTKILLME
cd /var/lib/jenkins/workspace/docker-spring-boot/spring-boot-nginx-docker-demo
mvn clean package
if [ -e "./volumes/app/docker-spring-boot.jar" ]
  then rm -f ./volumes/app/docker-spring-boot.jar \
        && cp ./target/docker-spring-boot.jar ./volumes/app/docker-spring-boot.jar \
    && docker-compose -p docker-spring-boot up -d \
    && docker restart docker-spring-boot \
    && docker restart docker-spring-boot-bak \
    && docker restart docker-nginx \
        && echo "update restart success"
  else mkdir volumes/app -p \
        && cp ./target/docker-spring-boot.jar ./volumes/app/docker-spring-boot.jar \
    && docker-compose -p docker-spring-boot up -d \
        && echo "first start"
fi

測試集群效果:

  • volumes/app放置了不同容器的日志,如該例子的logs、logs-bak

  • 停止任一SpringBoot容器docker stop docker-spring-boot,仍可通過url/api通過Nginx訪問

可以看出容器配置集群的以下優點:

  • 安全性高,每一個應用都只屬一個容器,通過特定配置才可與主機、其它容器交互

  • 統一配置文件,簡單粗暴的方式解決端口、路徑、版本等配置問題,如該項目即使運行了2個8080端口的SpringBoot容器而不需擔心端口的沖突、暴露問題,一切都在容器內解決

  • 省略手動應用安裝,易於遷移,由於版本、配置、環境等都已配置在Docker的配置文件中,所以不用擔心更換機器后出現的各種配置、環境問題,且通過鏡像拉取與容器運行可以省略如Nginx、Redis、Mysql等應用的安裝與配置

 

參考來源:toutiao.com/i6779098800825827852/

 


免責聲明!

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



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