preface

I learned docker-related content some time ago. Docker can realize data isolation and cross-platform, etc., to speed up the follow-up deployment of the project.

After understanding the docker deployment process, I learned the concept of CI/CD. Through simple configuration of GitLab and Docker, CONTINUOUS integration can be realized and production efficiency can be greatly improved.

General process of front-end deployment based on GitLab and Docker configuration:

The server listens to the remote git branch to see if there is a new submission –> the server pulls the corresponding branch code –> implements the dependent download and source code compilation based on node image –> builds the front-end image based on nginx image and compilation file –> runs the corresponding container based on docker-comedy.yml

Contact the front-end automation deployment tool previously implemented (for details, see: Front-end Automation Deployment from Scratch Node) and prepare to upgrade it to support Docker deployment.

conceived

On the basis of compatibility with traditional deployment modes, local compiled code can be uploaded and deployed, source code can be uploaded and remote compiled and deployed.

Consider that some simple projects may not need to use Docker-compose for container orchestration and can use the Docker run command directly.

Therefore, consider supporting project deployment in the following ways:

Deployment way legacy docker docker-compose
Local packaging builds dist
Source code remote package compilation

Thus, the user usage process is considered as follows:

Select project -> Select deployment mode -> upload source code or compiled code -> remote automatic deployment

It is divided into the following two implementation ideas:

  1. Upload the source code to the cloud, the cloud with the help ofDockerfileBased on thenodeMirror implementation depends on download, package compilation, based onnginxImage and compile file build front-end image, finally run the container.
  2. The project is compiled locally, packaged and uploaded to the cloud, directly based onnginxImage and compile file build front-end image, finally run the container.

Preparation before upgrade

To better understand the project implementation, prepare the following in advance:

  1. Familiar with docker deployment process andDockerfile,docker-compose.ymlGrammar rules
  2. Docker and Docker-compose are successfully installed on the remote server
  3. Node Basics

upgrade

Logical sorting module division

Firstly, the original project is logically sorted and divided into modules to clarify the functions of each module. The final file directory is shown as follows:

File compression upgrade supports filtering list

Since the source code needs to be packaged and uploaded this time, it is necessary to realize the filtering of node_modeles related files. Consider configuring the filter list based on the exclude field in the configuration file to implement the package filtering function.

Before compression, read the subfile name of the target file directory targetDir, exclude the files in the filter list excludeFiles, and return the array of filenames after filtering.

In the compression process, the old version uses archive.directory() to realize the compression of the entire file directory. Now, it is based on the file array in sequence. Fs.statsync (filePath).isdirectory () is used to determine whether the subfiles are folders. Archive. File () and archive. Directory () are used for corresponding packaging processing.

Compress. Js source code:

const fs = require('fs')
const archiver = require('archiver')
const join = require('path').join

function compress (targetDir, localFile, excludeFiles, homeDirName = 'web/') {
  return new Promise((resolve, reject) = >{
    // filter exclude files
    const filterDir = filterExcludeFiles(targetDir, excludeFiles)
    console.log('Compressing files... ')
    let output = fs.createWriteStream(localFile) // create file stream write
    const archive = archiver('zip', {
      zlib: { level: 9 } // set compress level
    })
    output.on('close'.() = > {
      console.log('Compression done! A total of ' + (archive.pointer() / 1024 /1024).toFixed(3) + 'MB')
      resolve('Compression complete')
    }).on('error'.(err) = > {
      console.error('Compression failed', err)
      reject('Compression failed')
    })
    archive.on('error'.(err) = > {
      throw err
    })
    archive.pipe(output) // save file by pipe
    // append file and dir
    filterDir.forEach(file= > {
      const filePath = join(targetDir, file)
      const stat = fs.statSync(filePath)
      if (stat.isDirectory()) {
        archive.directory(filePath, homeDirName + file)
      } else {
        archive.file(filePath, { name: file, prefix: homeDirName })
      }
    })
    archive.finalize() // make sure file stream write completely})}// filter exclude files
function filterExcludeFiles (targetDir, excludeFiles = []) {
  return fs.readdirSync(targetDir).filter(file= > {
    return(! excludeFiles.includes(file)) }) }module.exports = compress
Copy the code

Upgrade Terminal Color

Implement color differentiation display of terminal command based on colors, using the following:

const colors = require('colors')

colors.setTheme({
  silly: 'rainbow'.input: 'grey'.verbose: 'cyan'.prompt: 'grey'.data: 'grey'.help: 'cyan'.debug: 'blue'.info: 'blue'.error: 'red'.warn: 'yellow'.success: 'green'
})

console.log('Bold text'.bold)
console.log('Error occurred'.error)
Copy the code

Tip: Options such as deployment are still based on inquirer implementations.

New Dockerfile docker – compose. Yml

Here, Dockerfile supporting source code compilation is used as an example to introduce the front-end image construction process:

  1. referenceNode: LTS - alpine3.12(Base Version node image, smaller file)
  1. Switch to Ali source (if the download is slow, you can switch to Ali source)
  2. Specify working directory/tmp/cache(Inside the container)
  3. Add the current sibling directorypackage.json(Package-lock. json please add if it exists)
  4. Perform dependent installation
  5. Copy the current directory files to the working directory
  6. Execute compile instruction
  7. referencesocialengine/nginx-spa:latest(Nginx image with SPA-related configuration, listening address: /app/index.html)
  8. Copying node Images/tmp/cache/distTo nginx mirror/appUnder directory (folder can be customized after compilation)

Dockerfile

FROM node:lts-alpine3.12 as build

If the download is slow, you can switch to Ali source
RUN npm config set registry https://registry.npm.taobao.org

WORKDIR /tmp/cache

ADD package.json .
# enable package-lock.json if it exists
ADD package-lock.json .
RUN npm install

ADD.
Compile instructions can be customized
RUN npm run build

FROM socialengine/nginx-spa:latest as nginx
The folder can be customized after compiling
COPY --from=build /tmp/cache/dist /app
Copy the code

Docker-comemage. yml is simple, specifying the container name, image name, restart mode, mapping port (host port: container port) and other information.

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

docker-compose.yml

Version: "3.8" services: web: # Keep the container name and image name consistent with the configuration file container_name: spa_web restart: always image: spa/web:dev ports: - 8900:80Copy the code

Docker deployment process

In the main program, according to the user’s choice for deployment judgment, mainly divided into the following process

  1. Docker, docker-compose installation check
  1. uploadDockerfileordocker-compose.yml
  2. Build the Docker image
  3. Check whether a container with the same name exists before starting it. If it does, stop and delete it
  4. Use according to configurationdocker run ordocker-compose.ymlStart the container
  5. Displays the current running container status
  6. Prompt Complete deployment

tips:

  • If the network speed of the server is low, install the server in advancenodeandnginxDocker image to speed up subsequent deployment
    • Docker pull node: LTS – alpine3.12
    • docker pull socialengine/nginx-spa:latest

Spp.js docker

/ / docker process
Docker env check --> upload Dockerfile --> build image
const dockerFilePath = deployDir + releaseDir
await runCommand(ssh, `docker -v`.'/')
await uploadFile(ssh, getAbsolutePath(BUILD__MODE === 'dist' ? docker_file : docker_file__build), dockerFilePath + '/Dockerfile') // upload Dockerfile
console.log('5- Start building docker images... Please be patient. '.bold)
await runCommand(ssh, `docker build -t ${ image }. `, dockerFilePath)
console.log('6- Ready to start docker container... Please be patient. ')
if (DEPLOY__MODE === 'docker') {
  if ((await runCommand(ssh, `docker ps -f name=${ container_name }`)).indexOf('\n')! = = -1) {
    console.log('Existing container with same name, deleting container with same name... ')
    await runCommand(ssh, `docker stop ${ container_name }`.' ')
    await runCommand(ssh, `docker rm ${ container_name }`.' ')}await runCommand(ssh, `docker run --name ${container_name} -p ${ports} -d ${image}`, dockerFilePath)
} else {
  Upload docker-compose --> run docker-compose --> show container
  await runCommand(ssh, `docker-compose -v`.'/')
  await uploadFile(ssh, getAbsolutePath(docker_compose), dockerFilePath + '/docker-compose.yml') // upload docker-compose
  if ((await runCommand(ssh, `docker ps -f name=${ container_name }`)).indexOf('\n')! = = -1) {
    console.log('Existing container with same name, deleting container with same name... ')
    await runCommand(ssh, `docker stop ${ container_name }`.' ')
    await runCommand(ssh, `docker rm ${ container_name }`.' ')}await runCommand(ssh, 'docker-compose up -d', dockerFilePath)
}
// Displays the current running container
console.log('7- Currently running containers... '.bold)
await runCommand(ssh, 'docker ps', dockerFilePath)
console.log(` congratulations!${ name }Successful deployment '.success)
Copy the code

This completes the major upgrade of the project, refer to my-Auto-deploy for more details.

use

Here, two cases are selected for demonstration:

  • docker + source build
  • docker-compose + dist

This section uses the react online wallpaper as an example. Ports 8800 and 8900 are enabled on the react server.

  1. Pull code to local, install dependencies, perform local build, directory as shown below:

  1. The project is generated after constructionbuildFolder does not existpackage-lock.jsonFile, therefore modifiedThe configuration fileandDockerfileAs shown in figure

The configuration file

Dockerfile

  1. Run the deployer and select the appropriate information to start the deployment until the deployment is complete, as shown

Select the deployment

The deployment is successful (the container information is the expected result)

  1. Access the corresponding address to verify that the deployment is successful, as shown in the figure

  1. Modify thedocker-compose.ymlIf the port number is 8900, deploy it again, as shown in The figure

docker-compose.yml

Select the deployment

  1. Because a container with the same name exists, the deployment process stops and deletes the container, and then starts the container with the latest image, as shown in the figure

  1. Access the corresponding address to verify that the deployment is successful, as shown in the figure

The last

🎉 The project has been open source to Github welcome to download and use the follow-up will improve more functions 🎉 source code and project description

If you like, don’t forget star 😘. If you have any questions, please raise your questions about pr and issues.

Other articles:

Implement front-end automatic deployment of Nodes from scratch

React Hook implementation of online wallpaper site from scratch