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:
- Upload the source code to the cloud, the cloud with the help of
Dockerfile
Based on thenode
Mirror implementation depends on download, package compilation, based onnginx
Image and compile file build front-end image, finally run the container. - The project is compiled locally, packaged and uploaded to the cloud, directly based on
nginx
Image 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:
- Familiar with docker deployment process and
Dockerfile
,docker-compose.yml
Grammar rules - Docker and Docker-compose are successfully installed on the remote server
- 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:
- reference
Node: LTS - alpine3.12
(Base Version node image, smaller file)
- Switch to Ali source (if the download is slow, you can switch to Ali source)
- Specify working directory
/tmp/cache
(Inside the container) - Add the current sibling directory
package.json
(Package-lock. json please add if it exists) - Perform dependent installation
- Copy the current directory files to the working directory
- Execute compile instruction
- reference
socialengine/nginx-spa:latest
(Nginx image with SPA-related configuration, listening address: /app/index.html) - Copying node Images
/tmp/cache/dist
To nginx mirror/app
Under 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
- Docker, docker-compose installation check
- upload
Dockerfile
ordocker-compose.yml
- Build the Docker image
- Check whether a container with the same name exists before starting it. If it does, stop and delete it
- Use according to configuration
docker run
ordocker-compose.yml
Start the container - Displays the current running container status
- Prompt Complete deployment
tips:
- If the network speed of the server is low, install the server in advance
node
andnginx
Docker 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.
- Pull code to local, install dependencies, perform local build, directory as shown below:
- The project is generated after construction
build
Folder does not existpackage-lock.json
File, therefore modifiedThe configuration file
andDockerfile
As shown in figure
The configuration file
Dockerfile
- 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)
- Access the corresponding address to verify that the deployment is successful, as shown in the figure
- Modify the
docker-compose.yml
If the port number is 8900, deploy it again, as shown in The figure
docker-compose.yml
Select the deployment
- 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
- 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