Docker realizes resource isolation through Namespace of Linux, resource control by Cgroups, and efficient file operation through copy-on-write mechanism. In practical development, Docker can be used to provide one-time environment, build microservice architecture, and deploy unified environment.
preface
Although Docker has become a popular container technology around the world, unifying the environment to avoid environment configuration is one of the main attractions of Docker, but there are still many problems when using it. For example, I have thought about these problems when building my own container:
- How do I use the Jenkins container?
- If using the Jenkins container, how do I deploy the SpringBoot project from the Jenkins container? Is the project deployed through the Jenkins container interacting with files in the SpringBoot container? Can it be done? Or put the SpringBoot project into a Jenkins container and install Git, Maven, etc., which is not convenient.
- Use IDEA Docker plug-in can directly connect to the Docker server to create images and run containers, why also need Jenkins?
In the actual construction and deployment also found the corresponding answer:
- If Jenkins containers are used, this can make deployment more difficult because Jenkins often needs to configure a number of variables, such as Maven and Git, and should find another way out. Since Jenkins is a script CI tool, and Docker also has its own scripts, I should consider the integration of Docker scripts into Docker.
- In actual development, Jenkins may need not only the deployment of the project, but also the authentication of the developer. For example, developer A can only view the deployment of the specified project, and the administrator can view the deployment of all projects, but Docker is mainly used for image construction and container operation. There is no access to Github/GitLab code like Jenkins and no developer authentication, so Docker can only play a role in Jenkins to simplify the deployment process.
- Although IDEA plug-in can directly package the successful project deployment server Dcoker locally and create the image running container, for security, it is also necessary to create Docker CA authentication, download it to the local and then connect the Docker on the server, which is very inconvenient
Environment to prepare
When the answers to the self-questions are explored, the main responsibilities of each component are identified:
- Jenkins: Receive project updates and execute project packaging and Docker scripts
- Docker: Install the required application image and run container
- Git: Project information synchronization
Setting up the environment process:
-
Install the JDK
-
Install Maven
-
Install git
-
If you have permission problems, change the JENKINS_USER file in /etc/sysconfig/Jenkins to root or manually assign permissions
-
Install Docker Engine – Community
-
Install 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 Copy the code
DockerCompose can save you the trouble of executing docker runs multiple times as containers grow
Specific steps
-
The configuration file
1. SpringBoot project Dockerfile
FROM java:8 MAINTAINER Wilson # Unify container and server time ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # copy target/docker-spring-boot.jar to container app COPY ./target/docker-spring-boot.jar app/docker-spring-boot.jar EXPOSE 8080 ENTRYPOINT ["java"."-jar"."app/docker-spring-boot.jar"] # docker build -t docker-spring-boot/latest . Copy the code
2. Configuration 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 The port is not open to the public # ports: # - 8080:8080volumes: - ./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 links: -app volumes: nginx:1.17.6 Environment: TZ: Asia/Shanghai Restart: always expose: -80 ports: -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 Copy the code
3. Nginx
-
./volumes/nginx/nginx.conf
user nginx; worker_processes 2; Set the value to the same as the number of CPU cores error_log /etc/nginx/error.log crit; # Log location and log level 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 virtual host configuration include /etc/nginx/conf.d/*.conf; } Copy the code
-
/volumes/nginx/conf.d directory default.conf
upstream application { server docker-spring-boot:8080; } server{ listen 80;# monitor port server_name localhost;# the domain name 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; }}Copy the code
-
-
Jenkins deployment execution process
- Maven packages the Spring Boot project as project.jar
- Depending on whether the following processes are performed with the first project deployment:
- If the current mounted volume already contains the project JAR (that is, it is not run for the first time), run the following steps:
- Copy project.jar to overwrite the project.jar in the mounted volume
- Re-run the SpringBoot project container
- If the current mounted volume does not contain the project JAR (that is, not the first run), run the following steps:
- Create a directory for mounting a volume
- Copy project.jar to the mounted volume
- Docker-compose read docker-compose. Yml configuration create image start container
Jenkins script (Nginx container restart command can also be added if the Nginx configuration changes a lot) :
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" elsemkdir 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 Copy the code
Docker-compose up command can be used for image installation, so it saves the trouble of preparing image-related instructions in advance when only docker command is used.
Results of the test
- Check whether containers are started:
docker ps
- SpringBoot container run result If the container has port 8080 open, it can pass the http://url:8080/swagger-ui.html test. You can also check the SpringBoot log result of /volumes/app in Jenkins’ workspace. The path of SpringBoot log is set to app/logs. The app directory in the container has been mounted to the volumes/app directory of the current project.
- Nginx container run result: Visit http://url/swagger-ui.html to check whether the Nginx container successfully connected to the SpringBoot container and reverse proxy. You can also check the /volumes/ Nginx /logs Nginx log verification results in the Jenkins workspace
- Add or remove the Controller interface and push it to Git to see if the changed interface is accessible
The SpringBoot cluster is set up
To build SpringBoot from a container cluster, just make the following changes:
-
Docker-comemess. yml adds SpringBoot project redundancy, changes the redundant container name, distinguishes the log mount path, and changes the redundant container name
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: - 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 Copy the code
-
Nginx changes upstream in default.conf to add redundant container configuration
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;# monitor port server_name localhost;# the domain name 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; }}Copy the code
-
Jenkins added redundant container restart scripts
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" elsemkdir 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 Copy the code
Test cluster effect:
- Volumes /app put logs for different containers, such as logs and logs-bak in this example
- Stop any SpringBoot container
docker stop docker-spring-boot
, can still be accessed via Nginx via URL/API
You can see the following benefits of container-configured clustering:
- High security. Each application belongs to only one container and can interact with hosts and other containers only through specific configurations
- Unified configuration file, simple and crude way to solve the port, path, version and other configuration problems, such as the project even if the two 8080 port of the SpringBoot container without worrying about port conflicts, exposure problems, everything is solved in the container
- Manual application installation is omitted to facilitate migration. Since version, configuration and environment have been configured in the Docker configuration file, there is no need to worry about various configuration and environment problems after machine replacement. Besides, the installation and configuration of applications such as Nginx, Redis and Mysql can be omitted through image pulling and container running
Attached project address
spring-boot-nginx-docker-demo