Set up a project using GitLab CI

preface

After the review of product requirements, separate tasks, cut a release branch from the master branch, and cut the development branch of update or feature according to their respective tasks;

When developing, debugging or testing, push the code to the remote branch, and raise the merge request (hereinafter referred to as mr) to the test branch. GitLab CI automatically builds and deploys the project code to the test environment;

After the test, mr is raised to the release branch. After the development branches of the requirements are reviewed and merged, mr is raised from the release branch to the pre branch. GitLab CI automatically builds and deploys the project code to the pre production environment, and then carries out regression testing. If there is a problem, cut out the development branch from the release branch for modification, and repeat the previous process.

After the pre production environment is OK, move mr from the release branch to the master branch, and then click tag to go online. GitLab CI automatically builds and deploys the project code to the production environment, and then performs regression testing. If there is a problem, it will be released again.

At this point, the complete development process of one-time requirements has come to an end. GitLab CI helped us complete some repetitive work such as construction / deployment. I have been curious about this. Next, we will try to build a project using GitLab CI.

Build a new project

If you use GitLab CI in an existing project, you can skip this step and start from Start here

You can build the warehouse step by step according to the following steps, or you can clone the warehouse directly: gitlab-ci-example

Initialize project

New project folder

mkdir gitlab-ci-example
cd gitlab-ci-example

Initialize git and npm

git init
npm init -y

New project file

mkdir src build

New gitignore file

gitlab-ci-example/.gitignore

dist
node_modules

New editorconfig file

gitlab-ci-example/.editorconfig

# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

New index HTML file

gitlab-ci-example/src/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h1>Learn Gitlab CI</h1>
    </div>
  </body>
</html>

New main JS file

gitlab-ci-example/src/main.js

function appendElementToAPP({ tag = "div", content = "" }) {
  const appEle = document.getElementById("app");
  const newEle = document.createElement(tag);
  newEle.innerHTML = content;
  appEle.append(newEle);
}

appendElementToAPP({
  tag: "div",
  content: `append content by js on ${new Date().toUTCString()}`,
});

Create a new webpack Dev.js file

gitlab-ci-example/build/webpack.dev.js

"use strict";
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const resolve = (dir) => path.resolve(__dirname, "../", dir);

module.exports = {
  mode: "development",
  entry: {
    app: "./src/main.js",
  },
  output: {
    path: resolve("dist"),
    filename: "[name].[hash].js",
  },
  resolve: {
    extensions: [".js"],
  },
  devServer: {
    port: 8090,
    contentBase: resolve("dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: resolve("dist/index.html"),
      template: "src/index.html",
    }),
  ],
};

Create a new webpack Prod.js file

gitlab-ci-example/build/webpack.prod.js

"use strict";
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const resolve = (dir) => path.resolve(__dirname, "../", dir);

module.exports = {
  mode: "production",
  entry: {
    app: "./src/main.js",
  },
  output: {
    path: resolve("dist"),
    filename: "[name].[hash].js",
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      filename: resolve("dist/index.html"),
      template: "src/index.html",
    }),
  ],
};

Create an append element JS file

gitlab-ci-example/build/append-element.js.sh

const path = require("path");
const fs = require("fs");
const cheerio = require("cheerio");

const htmlFilePath = path.resolve(__dirname, "../dist/index.html");

fs.readFile(htmlFilePath, (err, data) => {
  if (err) {
    return;
  }
  const $ = cheerio.load(data);
  $("#app").append(
    `<div style="color: red;">append content by build on ${new Date().toUTCString()}</div>`
  );
  fs.writeFileSync(htmlFilePath, $.html());
});

Create a new deploy test SH file

gitlab-ci-example/build/deploy-test.sh

cp -rf dist/* /www/test/gitlab-ci-example

Modify package JSON file

gitlab-ci-example/package.json

{
  "name": "gitlab-ci-example",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "deploy-test": "build/deploy-test.sh",
    "dev": "webpack-dev-server --config build/webpack.dev.js",
    "build": "webpack --config build/webpack.prod.js && node build/append-element.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Install project dependencies

npm i -D cheerio webpack webpack-cli webpack-dev-server clean-webpack-plugin html-webpack-plugin

Running items

npm run dev

Open link in browser: http://localhost : 8090/, you should see:

Package project

npm run build

Open index HTML file, you should see:

At this point, the basic functions of the project have been set up. Next, start using GitLab CI in the project.

Using gitlab CIS in projects

Before using GitLab CI, you should prepare:

  • One ECS
  • A GitLab warehouse

Set up GitLab Runner

On the warehouse home page, click the Sidebar - Settings - CI / CD, jump to the CI / CD Settings page, expand the Runners option, and manually set the GitLab Runner according to the steps:

Installing GitLab Runner

According to the system architecture, download and install the corresponding software package, View details

# Download (package for amd64)
curl -LJO https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb

# If the download is too slow, it is recommended to copy to the remote through the scp command after the local download, such as
# scp ~/gitlab-runner_amd64.deb yourUserName@yourIPAddress:/home/yourUserName

# install
sudo dpkg -i gitlab-runner_amd64.deb
# output
Selecting previously unselected package gitlab-runner.
(Reading database ... 67015 files and directories currently installed.)
Preparing to unpack gitlab-runner_amd64.deb ...
Unpacking gitlab-runner (13.0.1) ...
Setting up gitlab-runner (13.0.1) ...
GitLab Runner: detected user gitlab-runner
Runtime platform                                    arch=amd64 os=linux pid=28968 revision=21cb397c version=13.0.1
gitlab-runner: Service is not installed.
Runtime platform                                    arch=amd64 os=linux pid=28975 revision=21cb397c version=13.0.1
gitlab-ci-multi-runner: Service is not installed.
Runtime platform                                    arch=amd64 os=linux pid=28993 revision=21cb397c version=13.0.1
Runtime platform                                    arch=amd64 os=linux pid=29039 revision=21cb397c version=13.0.1

# If you receive an error like the above, run the following command. If you can output information, it means normal
sudo gitlab-runner status
# output
Runtime platform                                    arch=amd64 os=linux pid=29971 revision=21cb397c version=13.0.1
gitlab-runner: Service is running!

For the error information above, you can see this gitlab issue

Register gitlab runner

Start to register. Here is an example of Linux, See other systems here

# register
sudo gitlab-runner register
# output
Runtime platform                                    arch=amd64 os=linux pid=31237 revision=21cb397c version=13.0.1
Running in system-mode.

# Specify GitLab instance URL
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://gitlab.com/

# Enter the registration token (copy from project settings CI/CD settings Runners)
Please enter the gitlab-ci token for this runner:
JhXh7o********yDXATd

# Enter description
Please enter the gitlab-ci description for this runner:
[hostname]: runner-001

# Enter associated label
Please enter the gitlab-ci tags for this runner (comma separated):
runner-001-tag
# output
Registering runner... succeeded                     runner=JhXh7oEx

# Select the execution environment. The shell is selected here
Please enter the executor: virtualbox, docker-ssh+machine, kubernetes, parallels, shell, ssh, docker+machine, custom, docker, docker-ssh:
shell
# output
Runner registered successfully. Feel free to start it, but if it\'s running already the config should be automatically reloaded!

After downloading, installing and registering the Runner, return to the CI / CD Settings page. You should now be able to see the Runner associated with the project

Configuring gitlab CIS

After setting the GitLab Runner, we can start configuring gitlab CIS and creating new ones GitLab CI YML file

gitlab-ci-example/.gitlab-ci.yml

# Job name
job-test:
  # stage
  stage: test
  # Trigger condition: when the test branch is updated
  only:
    - test
  # Assign work to Runners with specific tags
  tags:
    - runner-001-tag
  # script
  script:
    - npm install
    - npm run build
    - npm run deploy-test

By default, GitLab Runner will not run work without tags, so here we specify the tag set when registering GitLab Runner: runner-001-tag, View more GitLab CI/CD configuration options

If you do not want to set tags, you can modify the configuration of GitLab Runner, and check Run untagged jobs to allow GitLab Runner to run tasks without tags.


Save Gitlab ci After the YML file, push the changes to the remote warehouse

Trigger GitLab CI

After the configuration file is available, we need to trigger it. We need to cut out a test branch from the branch containing the above changes and submit it to the remote to trigger the GitLab CI (new submission and merging of test branches will trigger the CI). Of course, it is also possible to create a test branch through the graphical interface

git checkout test
git push -u origin test

On the warehouse home page, click the Sidebar - CI / CD - Pipelines to view all CI records of the current warehouse, similar to the following:

Problems encountered

1. mkdir: cannot create directory '/home/gitlab-runner/builds/3-1Hb5zy': Permission denied

 Running with gitlab-runner 13.0.1 (21cb397c)
   on runner-001 3-1Hb5zy
Preparing the "shell" executor 00:00
 Using Shell executor...
Preparing environment 00:00
 Running on xx-ubuntu...
Getting source from Git repository 00:00
 mkdir: cannot create directory '/home/gitlab-runner/builds/3-1Hb5zy': Permission denied
Uploading artifacts for failed job 00:00
 mkdir: cannot create directory '/home/gitlab-runner/builds/3-1Hb5zy': Permission denied
 ERROR: Job failed: exit status 1

Reason:

After the code is push ed to the remote, the above error is reported during the construction. GitLab Runner uses the GitLab Runner user during the construction. When creating the directory, you will be prompted that the permission is insufficient. Try to view the directory information:

# View file and directory information
ls -alF /home/gitlab-runner
# drwxr-xr-x 4 root          root          4096 Jun  2 17:45 builds/

The permissions and permission groups of the current directory are root. The gitlab runner user is not under the root permission group, so he has no permission to operate.

Think about it 🤔 Something is wrong. GitLab Runner is used to build GitLab Runner, but why is the builds directory under the root permission group? Recall the operations related to the root user that have been done before. After confirmation and consulting the data, it is found that the root user (--user root) was specified during the manual installation of the service (GitLab Runner install) before this build:

# Install the service, specify the working directory, and specify that the user running the task is the root user
sudo gitlab-runner install --working-directory /home/gitlab-runner --user root

How to solve:

Delete the builds directory, uninstall and reinstall the gitlab runner service, and point the user associated with the service back to the gitlab runner user

# stop service
sudo gitlab-runner stop
# Uninstall service
sudo gitlab-runner uninstall
# Reinstall service, specify working directory and user
sudo gitlab-runner install --working-directory /home/gitlab-runner --user gitlab-runner
# Full configuration
# sudo gitlab-runner install --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitlab-runner --syslog --user gitlab-runner
# check
sudo gitlab-runner verify
# Start service
sudo gitlab-runner start
# View status
sudo gitlab-runner status
# View file and directory information again
ls -alF /home/gitlab-runner
# drwxrwxr-x 3 gitlab-runner gitlab-runner 4096 Jun  3 16:21 builds/

Now the permissions of the builds directory are returned to the gitlab runner user. Find the retry button associated with this work on the Pipelines or Jobs page of the gitlab warehouse, and click the button to try to run the build again

2. bash: line 92: npm: command not found

 Running with gitlab-runner 13.0.1 (21cb397c)
   on runner-001 3-1Hb5zy
Preparing the "shell" executor  00:00
 Using Shell executor...
Preparing environment 00:00
 Running on VM-0-5-ubuntu...
Getting source from Git repository  00:03
 Fetching changes with git depth set to 50...
 Reinitialized existing Git repository in /home/gitlab-runner/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example/.git/
 Checking out 4e716630 as test...
 Skipping Git submodules setup
Restoring cache 00:00
Downloading artifacts 00:00
Running before_script and script  00:00
 $ npm install
 bash: line 92: npm: command not found
Running after_script  00:00
Uploading artifacts for failed job  00:00
 ERROR: Job failed: exit status 1

Reason:

After the service is reinstalled and the retry is built, the above error is reported because the environment of gitlab runner user is not installed with node (by default, nodes installed on root or other users cannot be accessed in the environment of gitlab runner user)

How to solve:

Log in to the server, switch to the gitlab runner user, install nvm, and then install node

# Switch to root
sudo su
# Log in to gitlab runner user
su -l gitlab-runner
# Install NVM( https://github.com/nvm-sh/nvm ), if you access script 443, try to install NVM in other ways or install node directly
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
# View nvm
nvm ls
# Install node (up to now, the latest LTS version is 12.18.0, and you can choose the version to install by yourself)
nvm install 12.16.2
# View node and npm versions
node -v
npm -v

Now the gitlab runner user's environment has installed node. After happily trying to retry, he found that it was still bash: line 92: npm: command not found. For a time, he thought it was an illusion that the service did not detect the existence of node. After trying to reinstall and restart the gitlab runner service, retry still failed.

After calming down and looking up a large number of similar cases, it is preliminarily judged that the environment variables are not loaded, that is, the nvm is not loaded. Try to manually load ~/ bashrc file:

before_script:
  - source ~/.bashrc

After retry ing again, it still fails. Finally, it still fails at ~/ profile and ~/ Some new ideas are found in the notes in the headers of the two bashrc configuration files:

~/.profile

# ~/.profile: executed by the command interpreter for login shells.
# ...

Literal translation: ~ / profile: executed by the command interpreter for the login shell.

~/.bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# ...

Literal translation: ~ / bashrc: executed by bash (1) on a non login shell.

In the above information, the login and non login states are mentioned. The configuration file will only be executed in the corresponding state. It is found by adding debugging information that ~/. will not be loaded when gitlab runner performs task construction bashrc file, only ~/ Profile file; When you log in to the server through ssh, both files will be loaded. Are you confused 🤔, This is because ~/ At the beginning of the profile file, the environment (bash) determines whether to load ~/ bashrc file, the specific code is as follows:

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

To solve the problem that the npm command cannot find this problem, you need to Add the code to load nvm on the profile Profile:

# Edit profile
vi ~/.profile
# allocation nvm Load, add the following code to the configuration file( https://github.com/nvm-sh/nvm#installing-and-updating)
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
# After saving the configuration file, reload the configuration file
source ~/.profile

3. sh: 1: build/deploy-test.sh: Permission denied

$ npm run deploy-test
> gitlab-ci-example@1.0.0 deploy-test /home/ubuntu/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example
> build/deploy-test.sh
sh: 1: build/deploy-test.sh: Permission denied
npm ERR! code ELIFECYCLE
npm ERR! errno 126
npm ERR! gitlab-ci-example@1.0.0 deploy-test: `build/deploy-test.sh`
npm ERR! Exit status 126
npm ERR!
npm ERR! Failed at the gitlab-ci-example@1.0.0 deploy-test script.
# ...

Reason:

# In the project build directory (similar to: /home/ubuntu/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example), view the permission information of the deployment script
ls -alF ./build/deploy-test.sh
# -rw-rw-r-- 1 ubuntu ubuntu   42 Jun  2 19:40 deploy-test.sh

Discover and search through the above commands Related issues , found deploy test The SH file cannot be executed because it does not have executable permissions

How to solve:

  1. Directly change the deploy test SH file permissions
# Indicates deploy test SH file is executable
git update-index --chmod=+x ./build/deploy-test.sh
# Changes will be directly entered into the staging area. The git state of the editor may indicate that there are new changes. After ignoring and directly submitting this change, the git state status will be updated
git commit -m 'Make build.sh executable'
# Submit to remote, master, test or other branches
git push
  1. Execute deploy-test sh file
# package.json
- "deploy-test": "build/deploy-test.sh",
+ "deploy-test": "sh build/deploy-test.sh",

4. /www/test/gitlab-ci-example: No such file or directory

$ npm run deploy-test
> gitlab-ci-example@1.0.0 deploy-test /home/gitlab-runner/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example
> build/deploy-test.sh
/www/test/gitlab-ci-example: No such file or directory
Please create this directory and then assign the directory permissions to the gitlab-runner user.
You can execute the following command as root:
mkdir /www/test/gitlab-ci-example
chown gitlab-runner /www/test/gitlab-ci-example

Reason:

Build/deploy-test The SH script will copy the built code to the /www/test/gitlab-ci-example directory. Therefore, you need to create this directory before building

How to solve:

Refer to build/deploy-test For the prompt information printed in the SH script, create a new directory and assign directory permissions:

# Create a new directory (use root or other gitlab runner users)
mkdir /www/test/gitlab-ci-example
# Assign gitlab runner user folder permissions
chown gitlab-runner /www/test/gitlab-ci-example

summary

At this point, the CI can finally run through. The content of the deployed page is as follows, Click to view:

Adopted Gitlab ci YML configuration file, you can handle it in various stages of construction, for example, you can_ Script and after_ The script phase calls the nailing robot interface to synchronize the deployment status to individuals / groups in time:

before_script:
  # Nail notification nail group
  - curl -X POST 'https://oapi.dingtalk.com/robot/send?access_token=xxx&xxxx'

The notification is similar to the following:

More about Gitlab ci For the configuration information of the YML file, see Official documents

Making good use of CI / CD will greatly improve team collaboration and development efficiency. Everything is difficult at the beginning. There must be resistance at first. After crossing this barrier, there is another barrier waiting for you [manual dog head]

The warehouse link of the sample project is as follows. Welcome to star 🌟:

github repository (template): https://github.com/Lsnsh/gitl...

gitlab warehouse: https://gitlab.com/Lsnsh/gitl...

Command summary

# View gitlab runner related processes
ps aux|grep gitlab-runner

# Register gitlab runner
sudo gitlab-runner register

# Reinstall gitlab runner service
# stop service
sudo gitlab-runner stop
# Uninstall service
sudo gitlab-runner uninstall
# Reinstall service, specify working directory and user
sudo gitlab-runner install --working-directory /home/gitlab-runner --user gitlab-runner
# Full configuration
# sudo gitlab-runner install --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitlab-runner --syslog --user gitlab-runner
# check
sudo gitlab-runner verify
# Start service
sudo gitlab-runner start
# View status
sudo gitlab-runner status

# Copy files to remote host
# scp ~/gitlab-runner_amd64.deb yourUserName@yourIPAddress:/home/yourUserName
# eg: (copy the file ~/gitlab-runner_amd64.deb to the root directory of the remote host with the public IP of 110.120.130)
scp ~/gitlab-runner_amd64.deb root@110.120.130:/home/root

# View file and directory information
# eg: (view the /home/gitlab-runner directory)
ls -alF /home/gitlab-runner

# Switch to root
sudo su
# root user logs in to another user
# eg: (log in to gitlab runner user)
su -l gitlab-runner

# Indicates that the file is executable
# Git update index --chmod=+x file path
# Indicates that the file is not executable
# Git update index --chmod=-x file path
# eg: (indicates that the./build/deploy-test.sh file is executable)
git update-index --chmod=+x ./build/deploy-test.sh

# Assign file or folder permissions to users
# chown username file or folder path
# eg: (assign gitlab runner user /www/test/gitlab CI example folder permission)
chown gitlab-runner /www/test/gitlab-ci-example

Reference links

Tags: Linux Front-end DevOps

Posted by nevesgodnroc on Thu, 02 Jun 2022 06:55:17 +0530