preface

In normal development, we probably hear a few words: automation, CI/CD, DevOps, etc. Sometimes I resist, but sometimes I wonder, what are these things, and what’s in it for me as a front-end developer? Below I will implement a simple CI/CD process from theory to practice, and take you through the secrets of this process.

1. What is automation

My summary: for laziness. 😄

In the days before tools, many repetitive tasks were done by hand, such as harvesting fruit in fields and processing on assembly lines. With tools, we can free our hands and focus our energy on more important things. Let tools help us finish those repetitive tasks to improve efficiency. This is my understanding of automation. This is especially true in software development. In order to “get lazy”, automatic testing, automatic deployment, automatic construction and other types of tools emerge in an endless stream, so that we pay more attention to the quality of software and improve the life cycle of software.

2. CI/CD

2.1 Basic Concepts

CI/CD contains three core processes: Continuous Integration, Continuous Delivery and Continuous Deployment. Also called CI/CD pipeline. It is a best practice in agile development that enables software development teams to focus on meeting business requirements, code quality, and security.

2.2 Application Scenarios

Let me describe a simple working scenario to help you understand the process:

A and B are the developers of A project team, and D is the operation and maintenance personnel. A developed A login function, after the completion of the dev branch of is pushed to the remote, meanwhile B finish is also developing A shopping cart function also push the dev branch of remote, A and B to see if online environment function is normal, so let D to release A test version of the online, so he installed according to the requirements of project environment and release some configuration, Now A and B finally saw the code online, so they decided to put it in the online environment, and D started to configure the environment again. Unfortunately, there was A Bug, and THEN A and B corrected the Bug, and D continued to repeat the process… 😭

Later, The father of Party A pressed party A to check the function, so the project period had to be shortened. However, the development schedule of everyone was too busy, so A and B could not develop “CV” operation, resulting in endless bugs… Then they decided to take a different approach:

A and B continue to develop functionality, but begin to test their functionality using automated testing tools. D first set up Jenkins platform in the company, and then added some operation and maintenance scripts to write all the operations to be done. He also wrote different scripts for different environments. A and B after push, Jenkins side pull warehouse code automatically, and then execute the script to start building docker image and create the container to run code, after A while, refresh the page at A and B finally saw the function, then party A’s father saw function, finally relieved, A and B in the future more focused functions and business realization, There are fewer bugs, and SINCE D uses Docker, he no longer has to worry about environmental problems, nor does he need to do any operation manually, thus increasing the “fishing” time… (The above is a fabrication) 😂

Continuous Integration is A process in which A and B continue to integrate functionality into the project, then automate testing and continuously push remote repositories.

Continuous integration (CI) helps developers merge code changes into a shared branch or “trunk” more frequently (sometimes even daily). Once the changes made by developers to the application are merged, the system verifies the changes by automatically building the application and running different levels of automated testing (usually unit and integration tests) to ensure that the changes have not broken the application. This means that the test covers everything from classes and functions to the different modules that make up the entire application. If automated tests find conflicts between new code and existing code, CI can make it easier to quickly fix those errors.

However, the test environment version released by D with Jenkins is actually A Continuous Delivery process, in which the functions and automated test cases developed by A and B are released in the test environment for software quality evaluation. This process validates the results of different phases of the project and reduces software risk.

In Continuous Deployment, the build environment version is released on top of the previous process, where party dad and ordinary users can see your work and experience your functionality.

Actually this process from development to deployment of online time is few, this is the charm of CI/CD, in today’s products now crazy iteration, who released the function of the sooner, the better the more able to attract users, so stand in the user’s perspective, increased user retention rates, for it is a development and operational best practices of agile development.

To sum up, Docker solves the problems of uncoordinated environment and inefficient manual configuration.

Now that we know the basic concepts, let’s go through the next wave of practice. Let me show you how to deploy a Vue application using Jenkins and Docker.

3. Practice: Deploy a Vue application

3.1 Environment Preparation

Here are my personal environmental preparations:

  • Development environment: VSCode, Win10 OS
  • Linux cloud service with Docker and Docker Compose installed
  • A Github account with read and write permissions for the project

Docker Compose installation is not the focus of this article, you can find relevant articles online. One thing to note is that Github needs to access Jenkins through the extranet, so Jenkins must be deployed in the extranet environment (it can also be deployed on the Intranet, with the help of Gitlab).

3.2. Docker deploys Jenkins service

Jenkins is written in the Java language with cross-platform features and can run directly in the operating system. War file to install Jenkins, but the Java environment must be installed, so I prefer Docker to deploy a Jenkins service.

3.2.1 Install and run Jenkins Images

The following is the docker-comemage. yml file prepared by me. For more detailed configuration, please refer to Jenkins’ official documentation.

version: '3' 
services:
  jenkins:
    container_name: 'jenkins'
    image: jenkins/jenkins:lts
    restart: always
    user: jenkins:995
    ports:
      - "8081:8080"
      The following two ports can be added or not according to service conditions
      -"50000:50000"
      -"10051:10051" # Zabbix Server default port
    volumes:
      - /home/jenkins_data:/var/jenkins_home # Data persistence
      # map host docker command to Jenkins, so that you can use docker command in Jenkins container
      - /usr/bin/docker:/usr/bin/docker 
      - /var/run/docker.sock:/var/run/docker.sock
      # mapping time
      - /etc/localtime:/etc/localtime 
      Echo 'Asia/Shanghai' > /etc/timezone
      Timezone is a directory
      - /etc/timezone:/etc/timezone
Copy the code

You can then run the Jenkins service in the background using the docker-compose up -d command.

Note about user:

The default uid in the Jenkins container is 1000 and the user name is Jenkins.

# Enter Jenkins container
[root@centos7 ~]# docker exec -it jenkins bash
Check the uid and groupid
jenkins@ee70639cddd8:/$ id
uid=1000(jenkins) gid=995 groups=995
jenkins@ee70639cddd8:/$ whoami
jenkins
Copy the code

Jenkin does not have host operation permissions by default, but in the future, it needs to build and create containers in Jenkins, and only docker daemons on the host can have these permissions. Therefore, it is necessary to find the Groupid of the Docker Daemon on the host computer and assign it to Jenkins user whose UID is 1000. In this way, Jenkins can have the permission to operate the Docker Daemon.

Docker-compose: docker-compose: docker-compose

[root@centos7 ~]# cat /etc/group | grep docker
[root@centos7 ~]# docker:x:995:
Copy the code

Jenkins: /home/jenkins_data: /home/jenkins_data: /home/jenkins_data: /home/jenkins_data

 sudo chown -R 1000:1000 /home/jenkins_data
Copy the code

After running successfully, if Linux firewall is enabled, we need to add port permit:

# --permanent release
firewall-cmd --add-port=8080/tcp --permanent

Reload the firewall
firewall-cmd --reload
Copy the code
3.2.2 unlock Jenkins

Next we open the browser and typeIP + port numberI’ll be able to interview Jenkins. (If you notice that the page keeps saying Jenkins is in the works… So much to wait 😂…)As you can see, when initially entering, we need to enter the administrator password to unlock (Jenkins has a super administrator by defaultadmin), there are two ways to view your password.

Viewing Logs

docker logs -f jenkins
Copy the code

Look in the Jenkins container

# Go inside the Jenkins container and use the bash terminal
 docker exec -it jenkins  /bin/bash
 
# output password
cat /var/jenkins_home/secrets/initialAdminPassword
Copy the code

After entering the password, this page should appear if normal:

3.2.3 Installing plug-ins

Recommended installation

Click on the recommended plugin and wait patiently. If you are offline, please use proxy or offline installation message, this is because there are many plug-ins rely on Google services, so they cannot be downloaded, we can choose the following offline installation and download from Tsinghua source.

Offline installation and use tsinghua source download

After the plugin is installed (either successfully or successfully), you will go to a separate page to set up the administrator user. After the instance is configured, you will see Jenkins’ main page. Our first step is to configure the tsinghua source.

Let’s go into plug-in management and follow the following diagram:

Find and click on a green icon that shows the option to manage plug-ins:

Click advanced to find the upgrade site and replace the URL with Tsinghua Source submission:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json.

If you choose offline installation, first open the official plug-in, search for relevant plug-ins to download to the local, and then there is a plug-in upload function in the page just configured tsinghua source, we just need to upload and submit locally downloaded plug-ins.

Now you can install any GitHub plugins you want. Here are some of the GitHub plugins I want to introduce:

  • Git related: Git client, Github, etc
  • SSH related
  • Buid timeout Handle the build timeout
  • Dashboard View User panel
  • Folders
  • Thinbackup backup
  • AnsiColor highlight
  • Pass in parameters when building

Note: the latest version of the Chinese community provides a faster source than Tsinghua source, can be replaced with https://updates.jenkins-zh.cn/update-center.json.

3.2.4 How do I Manually Back up Jenkins Data

Docker-compose: Docker-compose: docker-compose: docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose: Docker-compose

Method 1: Commit mirroring

Find the Jenkins container ID using the following command and copy it:

docker ps -f name=jenkins
Copy the code

Create a new image from the container:

Docker commit 8 ea38ac038af Jenkins: v1.0Copy the code

Create a new container with this image and run:

# - ITD starts the interactive terminal and runs in the background
-v maps the container's TMP directory to the host's TMP directoryDocker run -itd -v/TMP :/ TMP Jenkins :v1.0Copy the code

If the container name is not specified, Docker will randomly generate a container name by default, which can be checked by using docker ps command. The container name I generated here is hungry_villani.

Next we go to the container and copy the data directory jenkins_HOME to TMP:

Use exec to enter the container
Copy the jenkins_home directory from the container to TMP
docker exec -it hungry_villani cp -r /var/jenkins_home /tmp
Copy the code

As the data volume mapping has been done above, we can use thetmpFind this in the directoryjenkins_homeThe directory:Next you can use LinuxmvCommand to move to the location where you want to backup (TMP directory will be cleared after reboot).

Method 2: Use--volumes-fromThe command

You can use the –volumes-from flag to create a new container to install the volume. We can see how to use it:

# --volumes from The Jenkins container
Use the tar command in Ubuntu to compress data
docker run --rm --volumes-from jenkins -v /tmp/backup:/backup ubuntu tar cvf /backup/backup.tar /var/jenkins_home 
Copy the code

Tar file, we can unzip the file to see the backup directory.

tar xvf backup.tar
Copy the code

This way, compared to the first way, does not create a new container to occupy memory, and is very convenient. If you want to know more, you can check out the official documentation.

Method 3: Run the cp command in one step

Without a word of command:

 docker cp 8ea38ac038af:/var/jenkins_home /tmp 
Copy the code

Cp command used in the container and copies of data between the host and the above command is inside the container jenkins_home directory copy to the hosting of TMP (first we have to find the container id), this way is more convenient than the above two, so to speak too much, but also to understand more easily than the above two, so highly recommend this way.

3.2.5 Jenkins’ authorization strategy

Common Jenkins permissions are controlled in the following ways, and they can be installed via plug-ins:

  • Matrix Authorization Strategy
  • Role-based Authorization Strategy
  • Github Authorization Strategy

Role-based authorization is enabled by clicking global Security Settings => after the plug-in is installed.

Next, go back to system Settings and scroll to the bottom to see that this feature is enabled:

The following operation is very similar to gitLab’s assignment of project permissions, so I won’t go into details.

3.2.6 How do I Upgrade Jenkins

(1) Stop the operation of the container first

docker stop jenkins
Copy the code

(2) Download tsinghua Source WAR package:

 wget http://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/latest/jenkins.war 
Copy the code

(3) Replace this WAR package with the war package inside Jenkins container:

docker cp jenkins.war <jenkins container_id>:/usr/share/jenkins/jenkins.war
Copy the code

(4) Rerun

docker start jenkins
Copy the code

3.3 Write Dockerfile for Vue project

How to write a Dockerfile to build an image on our existing Vue project? Here is the example in the Vue CookBook. I changed it slightly: Dockerfile

# build stage
FROM node:lts-alpine as build-stage
Image meta information, Maintainer project maintainer
LABEL maintainer="[email protected]"
# Working directory
WORKDIR /app
Copy all files from git repository to working directory
COPY . .
# installation CNPM
RUN npm install cnpm -g --no-progress --registry=https://registry.npm.taobao.org
Install project dependencies and package
RUN cnpm install --no-progress && cnpm run build

# production stage
# Production environment base Nginx image (the image above has been packaged as a static file)
FROM nginx:stable-alpine as production-stage
Use --from to copy the static files generated above to the nginx run directory
COPY --from=build-stage /app/dist /usr/share/nginx/html
# nginx exposed ports inside the container
EXPOSE 80
# Run the command
CMD ["nginx"."-g"."daemon off;"]
Copy the code

To prevent the working directory from becoming too large, you can add dockerignore to prevent files like node_modules from being copied in. In addition, don’t do too many redundant operations, docker images are stacked on top of each other (non-professional explanation), which will make the image become very large.

.dockerignore

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
.DS_Store
dist

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.dockerignore
Dockerfile
*docker-compose*

# Logs
logs
*.log

# Runtime data
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
pids
*.pid
*.seed
.hg
.svn

Copy the code

Note: the above two files must be placed under the project root directory. For more information about Dockerfile, check out the official documentation.

3.4 Configuring Jenkins Tasks

Next, we need to configure Jenkins. Here we take you step by step to complete it.

3.4.1 Configuring the SSH Connection to GitHub

After the code is pushed from local to GitHub, we need to use the Webkook function of GitHub to inform Jenkins to start the automatic task, but Jenkins needs to pull the code. The project I have here is a private project and requires public and private keys. We can use SSH to pull the code, so we need to add the private key on the host where Jenkins is running and the public key on the Github project.

Generating a key pair

# 4096 higher security
ssh-keygen -t rsa -b 4096 -C "youremail"
Copy the code

Add the private key to Jenkins credentials

You can find it in system Settings, check the type check SSH.

Adds the public key to the project’sDeploy keys

Configure in the repositorywebhook

Webhook is configured to notify Jenkins of pulling code when a push event is received.

3.4.2 Jenkins Task Configuration

Now that we have the SSH configuration basics in place, we are ready to configure the flow of the project. First, we need to create a free-style project, and then explain some of the basics of the project.

General

Source code management

Note: If a bunch of red errors appear in the Credentials file, your public and private keys are not configured correctly, and you need to check whether the public and private keys are working properly.

Build trigger The following build environment, build, build depends on your needs. For example, I don’t have any requirements on the build environment and after the build is completed (I use Docker to configure my own environment). Generally, after the build is completed, you can send notification to everyone, or do something else.

The build is mainly about executing the shell:

#! /bin/bash

# define variables
CONTAINER=${container_name}
PORT=${port}

# build Docker image does not generate a cache per build
docker build --no-cache -t ${image_name}:${tag} .

Check whether there are duplicate names and port usage
checkDocker() {
  RUNNING=$(docker inspect --format="{{ .State.Running }}" $CONTAINER 2>/dev/null)
  if [ -z $RUNNING ]; then
    echo "$CONTAINER does not exist."
    return 1
  fi

  if [ "$RUNNING"= ="false" ]; then
    matching=$(docker ps -a --filter="name=$CONTAINER" -q | xargs)
    if [ -n $matching ]; then
      docker rm $matching
    fi
    return 2
  else
    echo "$CONTAINER is running."
    matchingStarted=$(docker ps --filter="name=$CONTAINER" -q | xargs)
    if [ -n $matchingStarted ]; then
      docker stop $matchingStarted
      docker rm ${container_name}
    fi
  fi
}

checkDocker

Run the container
docker run -itd --name $CONTAINER -p $PORT: 80${image_name}:${tag}

Copy the code

The Build with Parameters plugin can be used to set the Parameters.

We need to pass four character arguments:Container_name (container name),Image_name (image name),Tag,Port (port to map)Save the configuration.

This step completes the simple configuration of the task. Now you can push a commit from local to test, or click on the project panelBuild With ParametersTo build.

If nothing else, you can see that the ball in the lower left corner turns blue, indicating a successful build:

3.4.3 Testing the deployment

We can go back to the host to see if the container we just created is running:

[root@centos7 ~]# docker ps | grep vue-demoFfbc893cd1e3 vue - demo: 1.0"Nginx - g 'daemon of..."5 minutes ago Up 5 minutes 0.0.0.0:8888->80/ TCP VUe-demoCopy the code

Enter your server IP +8888 in the URL to view the online Vue application:

And you’re done!

If you find that you can not enter, most of the firewall may not allow port 8888, then you can do the following operations:

You can view all port information first
firewall-cmd --list-all

Port 8888 is permanently allowed
firewall-cmd -add-port=8888/tcp --permanent

# restart firewall
firewall-cmd --reload
Copy the code

3.5 Common Problems

3.5.1 Permission denied is displayed after Jenkins is run

Docker logs -f Jenkins: docker logs -f Jenkins: docker logs -f Jenkins: docker logs -f Jenkins: docker logs -f Jenkins: docker logs -f JenkinsJenkins does not have read/write and execute permissions on host files.

/home/jenkins_data is the mapping directory of your host
sudo chown -R 1000:1000 /home/jenkins_data
# or
sudo chmod 777 -R /home/jenkins_data
Copy the code
3.5.2 The Firewall Fails to be accessed after an Enabling port is added

It is possible that the server’s security group has not opened the release, and you need to provide the site Settings to your cloud server.

3.5.3 Jenkins construction: Docker: Command not found

This is because we let Jenkins operate docker, Jenkins does not have the permission to operate Docker, you need to assign Jenkins a permission, see the details in my previous Jenkinsdocker-composeThe configuration.

4 summarizes

This article gives you a brief introduction to the CI/CD process and usage scenarios, and then puts the CI/CD process into practice by deploying a Vue application. In this process, we can see the Linux basic operations, Docker deployment, Jenkins work processes, such as knowledge, although I was a front-end developer, but with this knowledge, I have a whole in the whole project process of cognition, although the configuration is not very complicated, but for a more understanding of agile development processes.

Finally: thank you very much for reading this article, I am a current or a rookie, if the article has a mistake, welcome your correction!

5 reference

[1] Docker install Jenkins official documentation

[2] What is CI/CD? What about continuous integration, continuous delivery, and continuous deployment