Our development process is generally a new development branch, and then development, development package deployment to the test environment for testing. But there is a pain, especially in the big teams, we tend to a lot of people Shared a test machine, thus led to a problem, once someone is using this machine, so others can’t use the machine, because cut the branch leads to another person’s code is cut off, thus resulting in the insufficient test machine. The emergence of Docker can solve this problem well.

Note: Understanding of Docker and Gitlab-CI is required to read this article. Do not know about this aspect of knowledge, need to learn.

Train of thought

When we are ready to test each branch, we will generate a branch specific Docker image, which is based on Nginx. It will complete the packaging and deployment of the code (to Nginx), so as to realize the purpose of different branch code running on different Docker containers. This enables a machine to run multiple branches of code.

Step 1: Write a Dockerfile

Since we need to use Nginx, our image will be based on Nginx. If we need to do packaging, we will also need to use Node, assuming our project is under /home test.liweiji.com. We need to switch our branches and pull our own code first) :

Dockerfile:

# Based on node image
FROM node

# Set the work path similar to CD /home test.liweiji.com
WORKDIR /home/test.liweiji.com

# packaged to/home/test.liweiji.com/dist directory, of course, if dist to see their projects
RUN npm install \
    && npm run build

# Based on nginx images
FROM nginx

The default nginx configuration cannot be used directly, so we need to use our own nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
Copy the code

nginx.conf

# depending on the user you are running docker on, you will get 403 if you do not set it correctly
user root;

events {
    use epoll;
    worker_connections 102400;
}

http {
    # This can't be minimized, otherwise static styles won't work
    include mime.types;
    The following configuration depends on your project
    server {
        listen 80;
        server_name test.liweiji.com;

        location / {
            add_header Access-Control-Allow-Origin *;
            root /home/test.liweiji.com/dist;
            break; }}}Copy the code

Step 2: Generate the image and run the container

We log in to the test machine and go to /home test.liweiji.com

Different branches use different tags
docker build -t <image_name>:<tag> .
This example is 8080. Different branches can use different ports
docker run --name <container_name> -p 8080:80 -idt <image_name>:<tag>
Copy the code

So we have different branch code packaged into different Docker images. We can use docker PS to check whether our Docker container is running.

Note: If it does not run, an error occurs, but the docker run command does not tell us the exact cause of the error, we can use docker logs <container_name> to view the error message

Through the above two steps, we can achieve the package of different branch code to different Docker images, so that the test through different images, test different branch code.

However, this solution is not perfect enough, but also requires the developer to go to the test machine to cut the branch code, package the image to run the container. So is there a way to automate these operations, and the answer is yes, it’s Gitlab-CI.

Use GITlab-CI for automation

Gitlab-ci allows us to submit code and trigger gitlab-Runner to run a series of operations, such as install, package, deploy, etc.


    

So, we can do this through Gitlab-CI: when we commit our code to the remote end, we generate the corresponding image of the latest code of the branch and run the corresponding container of the image to achieve automation.

Step 1: Sign up for Gitlab-Runner

The real task execution of Gitlab-CI is in the charge of runner, so we need to register runner in a specific machine. We register runner through Gitlab-CI-multi-Runner. As for how to install Gitlab-Ci-multi-Runner, I won’t talk about it here, everyone go to Google.

rungitlab-ci-multi-runner registerTo register runner, we input URL, token, description, tag, executor and so on step by step. We find URL and token according to setting->pipeline on gitLab website.Here we only execute shell commands, so executor selects shell.

Step 2: compile.gitlab-ci.yml

We need to define the set of operations we want to do in.gitlab-ci.yml. We need the two steps described above: generate the latest image and run the container. But in order to ensure that every package is up to date, we need to have a cleanup task, so there are three steps:

# gitlab - cli variables look at https://docs.gitlab.com/ee/ci/variables/
The stages of job execution are executed sequentially
stages:
  - clean
  - build
  - run

# clean mirror
job1:
  stage: clean
  only:
    - /^liweiji.*$/ # liweiji under the branch
  tags:
    - test
  script:
    - docker stop test:$CI_COMMIT_REF_NAME
    - docker rm test:$CI_COMMIT_REF_NAME
    - docker image rm test:$CI_COMMIT_REF_NAME
  allow_failure: true The first attempt at clearing the image will fail, and the next task will fail
# Customize the job flow of the build phase
job2: # Custom name
  stage: build # specify the name of the operation for this stage
  only: # specify which branches will enter the process
    - /^liweiji.*$/ # liweiji under the branch
  tags:
    If you want other runners to perform the same operation, add the tag of the other runner
    - test
  script:
    # docker build, $CI_COMMIT_REF_NAME is the branch name, variable can be viewed at https://docs.gitlab.com/ee/ci/variables/
    - cd page/public-sale
    - echo `docker build -t test:$CI_COMMIT_REF_NAME . | awk -F "Successfully built " '{print $2}'`
job3:
  stage: run
  only:
    - /^liweiji.*$/ # liweiji under the branch
  tags:
    - test
  script:
    # $CI_COMMIT_REF_NAME is the branch name
    - docker run --name test:$CI_COMMIT_REF_NAME -p 8000:80 -idt test:$CI_COMMIT_REF_NAME
Copy the code

We have two types of Runners, Specific Runners and Shared Runners. Once we submit the code, we execute Shared Runners if the tag is not specified in the. Gitlab-ci. yml job. When specified, the Specific Runners corresponding to the tag are executed.

If the task is successful, we can see the execution of our task in Charge on our GitLab website.

Note: The correct task would be to generate the image, upload the image to the image repository, and then have the test pull the corresponding branch of the image run container. I’m doing this here because the Gitlab-Runner is on the same machine as the test machine.

Have a problem

Problem 1: Docker running nginx report 403

There are two reasons for this problem, one is permissions and the other is that the home page index.html does not exist, and we encountered the first reason. Nginx. conf = ‘root’; / / nginx.conf = ‘root’; / / nginx.conf = ‘root’; / /

user root;
Copy the code

Problem 2: The style is downloaded but does not work

This is also due to nginx configuration, because we reconfigured nginx ourselves, so some configuration is not done well. Nginx uses application/octet-stream if mime.types is not configured. So CSS can be downloaded but not processed and Resource interpreted as Stylesheet but transferred with MIME type text/plain warning The solution is to add include mime.types under the HTTP tag of nginx.conf;

http { include mime.types; . }Copy the code

Docker: Command not found

The reason is that. Gitlab-ci. yml job is not configured with tags, leading to the execution of share Runner, while Share Runner is not configured with Docker.

Su: User gitlab-runner does not exist

The reason is that our runner specified user as gitlab-runner, but our machine did not create this user, so there are two ways to solve the problem:

  1. useradd gitlab-runner
  2. Kill the Gitlab-Ci-multi-Runner process and run it as another user, instead of root
gitlab-ci-multi-runner run --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service root--syslog --user root
Copy the code

conclusion

Docker is an independent container, isolated from each other, we can deploy nginx and code for each Docker image, so as to use Docker to realize different code running under different development branches, so as to realize one machine multi-branch code running. Gitlab-ci can realize automated tasks, such as installation, packaging, deployment and a series of tasks, so we can use Gitlab-CI to realize the automation of Docker image generation and container operation, so as to avoid manual operation by users.