First posted on Jenkins Chinese community

Main points of this paper:

  1. Design a basic Spring Boot pipeline: build, upload, and deploy.
  2. Run the build logic using the Docker container.
  3. Automation of the whole experimental environment: including Jenkins configuration, Jenkins Agent configuration, etc.

1. Code warehouse arrangement

This experiment involves the following code warehouses:

% tree -L 1 ├─ 1-cD-Platform# Code related to experimental environment├ ─ ─ 1 - env - the conf# Environment configuration code - implement configuration independence1 - springboot └ ─ ─# Spring Boot application code and its deployment code
Copy the code

1- The directory structure of Springboot is as follows:

% cd1-springboot % tree -L 1 ├─ Jenkinsfile# pipelined code├ ─ ─ the README. Md ├ ─ ─ the deploy# Deploy code├ ─ ─ pom. XML └ ─ ─ the SRC# Business code
Copy the code

All codes are available on GitHub: github.com/cd-in-pract…

2. Prepare the experimental environment

Docker Compose + Vagrant was used for the experiment. The environment includes the following systems:

  • Jenkins * 1 Jenkins Master, automatic install plug-in, default user name password: admin/admin.
  • Jenkins Agent * 2 Jenkins Agent runs in Docker container and starts two of them.
  • Artifactory * 1 a commercial version of the artifact library. I applied for a 30-day business edition.

Vagrant is used to start the virtual machine for deploying the Spring Boot application. If your development machine cannot use Vagrant, the same effect can be achieved with VirtualBox. But there is one thing to pay attention to, and that is the network. To access services provided in the Docker container on a VM, you need to make corresponding adjustments on the DNS or hosts. All VM images use Centos7.

Additionally, all of my tutorials will use Artifactory as an artifact library. For the record, I do not receive any advertising fees from JFrog, the company that develops Artifactory products. I just want to try out commercial products to see how they deal with product management issues.

After starting Artifactory, add “Virtual Repository” and “Local Repository”. Please refer to Artifactory’s official documentation for details. If you’re currently using a Nexus, follow this tutorial and make some adjustments.

If you want to use an existing artifact library, you can modify settings-docker.xml in the 1-cd-platform repository to point to your own artifact library.

The recent overall structure of the experimental environment is as follows:

architecture.png

I say “recent” because the structure above is slightly different from that described in this article. This article has not covered Nginx and Springboot configuration sharing, but it does not affect your overall understanding.

3. Springboot application pipeline

The Springboot pipeline has two phases:

  1. Build and upload artifacts
  2. The deployment of application

All the logic of the pipeline is written in Jenkinsfile. Next, the two phases are described separately.

3.1 Build and upload products

Core code of this stage:

docker.image('Jenkins - docker - maven: 3.6.1 track - jdk8')
.inside("--network 1-cd-platform_cd-in-practice -v $HOME/.m2:/root/.m2") {
    sh """ mvn versions:set -DnewVersion=${APP_VERSION} mvn clean test package mvn deploy """
}
Copy the code

It starts a container with Maven, and then compiles, unit-tests, and publishes artifacts within the container.

MVN versions: set-dnewVersion =${APP_VERSION} changes the version in the POM. XML file. This allows you to commit one version at a time.

3.2 Deploying Applications

Note: This section requires some knowledge of Ansible.

First look at the entrance to the deployment script 1 – springboot/deploy/playbook. Yaml:

---
- hosts: "springboot"
  become: yes
  roles:
    - {"role": "ansible-role-java". "java_home": "{{JAVA_HOME}}"}
    - springboot
Copy the code

Install the JDK first, and then Spring Boot. Install JDK, using ready-made Ansible role: github.com/geerlingguy… .

Focus on the core logic of Spring Boot deployment. It mainly includes the following parts:

  1. Create an application directory.
  2. Downloads the specified version of the artifact from the artifact repository.
  3. Generate Systemd Service files (to implement servitization).
  4. Start the service.

The above step implementation in 1 – springboot/deploy/roles/springboot.

The core code of the pipeline deployment phase is as follows:

docker.image('williamyeh/ansible:centos7').inside("--network 1-cd-platform_cd-in-practice") {

  checkout([$class: 'GitSCM'.branches: [[name: "master"]], doGenerateSubmoduleConfigurations: false.            extensions: [[$class: 'RelativeTargetDirectory'.relativeTargetDir: "env-conf"]], submoduleCfg:[].            userRemoteConfigs: [[url: "https://github.com/cd-in-practice/1-env-conf.git"]]])

  sh "ls -al"

  sh """ ansible-playbook --syntax-check deploy/playbook.yaml -i env-conf/dev ansible-playbook deploy/playbook.yaml -i env-conf/dev --extra-vars '{"app_version": "${APP_VERSION}"}' """
}
Copy the code

It first clones the variable repository code, then performs a syntax check on the Playbook, and finally executes the ansible-playbook command for deployment. App_version of the extra-vars parameter is used to specify the version of the application to be deployed.

3.3 Simple deployment of a specified version

Easy deployment of a specified version is implemented in 1-Springboot /Jenkinsfile. The core code is as follows:

  1. Pipeline acceptance parameter
parameters { string(name: 'SPECIFIC_APP_VERSION'.defaultValue: ' '.description: ' ')}Copy the code
  1. If the version is specified, the build phase is skipped and the deployment phase is performed directly
stage("build and upload") {// If the deployment version is not specified, the build is performed
      when {
        expression{ return params.SPECIFIC_APP_VERSION == ""}}// The logic to build and upload artifacts
      steps{...}
}
Copy the code

It is “easy” because only the version of the artifact is specified at deployment time, not the version of the deployment logic and configuration. The versions of all three need to be synchronized for deployment to be truly accurate.

4. Configure management

All configuration items are stored in the 1-env-conf repository. The configuration of this repository is read by Ansible for deployment.

Putting configuration in a Git repository has two benefits:

  1. Configure versioning.
  2. Any configuration changes can be reviewed.

Benefits don’t mean no costs. Developers need to start caring about configuration (I’ve noticed that many developers ignore the importance of configuration management). .

Configuration management is not the focus of this article, which will be covered later.

5. Detailed introduction of the experimental environment

In fact, the whole experiment has two heavy workload: one is the design of Spring Boot assembly line itself; The second is the automation of the whole experimental environment. Readers were able to activate the entire environment with one or two simple commands because I did a lot of automation. I think it is necessary to introduce these efforts in this article. This will not be covered in detail in the following articles.

5.1 Troubleshooting The Docker container started in the pipeline cannot be accessedhttp://artifactory

In the pipeline, we need to upload the artifact to the Artifactory (settings.xml is configured with the repository address http://artifactory:8081), but find that the host cannot be resolved. This is because the Docker container in the pipeline resides on a different network than the one created by Docker Compose. Therefore, the solution is to add Docker containers in the pipeline to Docker compose’s network.

The solution is to start the container with the parameter –network 1-cd-platform_cd-in-practice

5.2 Jenkins starts initialization for the first time

When Jenkins is started without any setup, a configuration wizard appears. The process has to be manual. I hope this step is also automated. The Groovy script in the init.groovy.d/ directory will be executed when Jenkins boots up.

5.3 How can I Access the VMhttp://artifactory ?

http://artifactory is deployed in a Docker container. To deploy artifacts of a Spring Boot application to a virtual machine, you need to pull artifacts from http://artifactory, that is, to access services provided in the container from the virtual machine. The network between the VM and the container is abnormal. So what to do? The author’s solution is to use the HOST IP to do the transfer. Add a host record to the virtual machine:

machine.vm.provision "shell" do |s|
    s.inline = "echo '192.168.52.1 artifactory' >> /etc/hosts"
end
Copy the code

Vagrant’s provision technology is used to automatically execute the inline shell when the command Vagrant Up is used to start the virtual machine. 192.168.52.1 is the IP address of the virtual host. So, when you visit http://artifactory:8081 in the virtual machine, you actually visit http://192.168.52.1:8081.

The network structure can be summarized as follows:

network.png

Afterword.

Remaining issues:

  1. The deployment-time artifact version, configuration version, and deployment code version are not synchronized.
  2. Springboot’s configuration is written to artifacts, and there is no separation of artifacts from configuration items.

These remaining problems will be solved one by one in the later stage. Just as in reality, there are often legacy issues to face with legacy projects.

The appendix

  1. Nginx: jenkins-zh.cn/wechat/arti…
  2. Showme. Codes /2017-06-12…

Author: Zhai Zhijun