Docker open source application container engine, if you are from the back-end developer, I believe that this technology should be understood or familiar with, and for many front-end developers, maybe just stay at the stage of hearing, even do not know what it is? I don’t need to know, for example, I don’t really know what it is, but if I want to be a veteran front-end, that’s a gap that needs to be filled. Salted fish also want to have a dream, maybe one day can jump longmen!
This article takes a closer look at Docker and its uses by building a full-stack Node.js application with web front-end code and a mongoDB database.
What is a Docker
Docker is an open source application container engine, which is based on the Go language and complies with the Apache2.0 protocol. Docker allows developers to package their applications and dependencies into a lightweight, portable container that can then be distributed to any popular Linux, Windows machine, or virtualization.
I don’t understand. Can you explain Docker’s past life in a popular way?
In 2010, a group of young IT guys in San Francisco founded a company called dotCloud. But it didn’t stick, so it opened source, and it became so popular that it had to be renamed awesome, and Docker came into being.
Before Docker, how to simulate an isolated system environment? The answer is virtual machine, we should not be unfamiliar, many developers inside the computer will install VMWare, through it, we can change out of several sub-computers, a window11, a CentOS, INSTALL MY favorite QQ, wechat and other software, many sub-computers isolated from each other, do not affect each other, zizi! But several G, dozens of G at every turn, the disk can not bear ah, but also slow startup.
Before the appearance of Docker, virtual machines were the Internet celebrities in the industry in terms of environmental isolation, but their disadvantages were serious. Docker container technology is also a virtualization technology, which is light, fast and integrated. It only needs MB level or EVEN KB level, unlike virtual machines, which need to simulate an operating system. Docker only needs to simulate a small scale environment (like a “sandbox”).
No, I want to see the data comparison, I just believe, arrange….
Docker core concepts
In the last section, we learned that Docker is a container virtualization technology, which is lighter, faster and easier to integrate. Next, we will have a quick understanding of its core concepts before entering our topic today, which will be better understood in code writing.
Docker’s three core concepts:
- Image
- Container
- Repository
The above diagram can reflect the relationship among the three. It should be noted here that we say Docker is a container technology, but Docker itself is not a container. It is a tool for creating containers and an application container engine.
A mirror, or Docker image, is a special file system. In addition to providing programs, libraries, resources, and configuration files required by the container runtime, it also contains some configuration parameters (such as environment variables) prepared for the runtime, and the image does not contain any dynamic data.
We can have a bunch of images that we want to store, and then we can go anywhere and use it to create a container environment, and then we need a repository for that, a Docker repository.
Is there a repository where everyone can store images? No, if there is a problem with the image, the container will hang when it is created. Therefore, there needs to be a role responsible for the management of Docker images, which is the Docker Registry service (similar to the warehouse administrator). There is also a public Registry service, the Docker Hub (a bit like our NPM marketplace), which houses many high quality official images.
We can also customize our image through the Dockfile file, which will be covered later
Through the above introduction, I believe you should also have a general understanding of Docker, here provides some commonly used Docker commands,
# container$docker run // Create and start container $docker start // start container $docker ps // view container $docker stop // stop container $docker restart // view container $ Docker attach // Enter container $dockerexec// Check the container $dockerexport// Import container snapshot $docker rm // delete container $dockerlog// View logs# image$Docker search // Retrieve image $Docker pull // Get image $Docker images // List image $Docker image ls // List image $docker RMI // Delete image $ Docker image rm // Delete image $docker save // Export image $docker load // import image# Dockfile custom image and common instructions$docker build // build the image $docker run // run the image COPY // COPY the file ADD // advanced COPY CMD // container start instruction ENV // environment variable EXPOSE // EXPOSE interface# service$docker -v $docker -version $systemctl start docker // Start docker $systemctl stop Docker // Disable docker $systemctlenable$service docker restart $service docker stop // Stop the docker serviceCopy the code
Create a Hello-world container
First, I need to download the Docker download address. I downloaded the Window Docker Desktop. Next, CHECK whether the version information has been downloaded successfully.
I downloaded version 20.10.11
Then pull the official Hello-world image of the Docker Hub,
Create and execute containers,
Docker image ls/docker image prune docker image prune ls/docker image prune ls/docker image prune ls/docker image prune
Creating the Node program
Node.js and package.json: Node.js server.js and package.json
const express = require("express");
const app = express();
const port = 8080;
app.get("/".async (req, res) => {
res.setHeader("Content-Type"."text/html");
res.status(200);
res.send(" Hello! Front-end evening class
");
});
app.listen(port, () = > {
console.log(`Example app listening at http://localhost:${port}`);
});
Copy the code
{
"name": "docker-example"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
"start": "nodemon server.js"
},
"author": "Front-end evening"."license": "ISC"."dependencies": {
"express": "^ 4.17.2"}}Copy the code
Run NPM run start
The problem with different Node versions
For the server.js file above, we add the following code:
// ...
const myPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve("good");
}, 300);
reject("bad");
});
myPromise.then(() = > {
console.log("this will never run");
});
Copy the code
Then run Node < 15 and Node >= 15 respectively to get two different results,
Node < 15
(node:764) UnhandledPromiseRejectionWarning: something happened (Use `node --trace-warnings ... ` to show where the warning was created) (node:764) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:764) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Copy the code
Node >= 15
node:internal/process/promises:218
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "recipe could not be generated".] {
code: 'ERR_UNHANDLED_REJECTION'
}
Copy the code
A high version (Node >= 15) results in a crash (ERR_UNHANDLED_REJECTION) which is an unhandled rejected Promise error.
Now assume that for some reason this application must be running on Node V14 or earlier to work (ignore using try… Catch). Every developer on the team must be ready to develop and run in this environment, but our company has a new application to run on Node V17!
So how do you solve this problem? Answer: the Docker
Create Dockerfile
In the previous section, we introduced the problem of two different versions of Node causing unhandled promises to be rejected. We introduced how to use Docker to solve this problem, which is actually very simple. We need a Node < 15 runtime environment to ensure that our application does not crash. Docker Hub allows you to search for images of Nodes, and there are many versions to choose from.
Of course, we do not need to directly use docker pull node to pull the node image, as mentioned earlier Dockerfile can be customized image, it automatically determines whether the current machine has a Node image, if not, then automatically pull docker Hub. Take a look at our Dockerfile:
# Select the image you want first, The node version running in Alpine is currently the most popular FROM Node: 14-Alpine3.12 # working directory # This is where you will be in the container WORKDIR /usr/src/app # wildcard used to ensure package.json and Package-lock. json is copied # COPY the source directory of the container's working directory COPY package*.json./ # Install the application rely on RUN NPM install # RUN NPM ci if you are building code for production --only=production # Bundle application source COPY.. # configure this port to be accessible from outside the container # EXPOSE 8080 required for the browser to send HTTP requests to Node applications # CMD to run at Docker Run time NPM run start CMD [" NPM ", "run", "start"]Copy the code
Ok, our Dockerfile file has been created successfully, the Dockerfile directive in the above code comments also have made a brief introduction, more detailed instructions can be Google search, but you may be curious above configuration file, why COPY needs to execute twice, the last COPY. Why copy package*. Json above instead of copying the entire directory?
Docker layer and cache
It is necessary to COPY twice, because Docker has layers. Every command executed will create another layer based on the layer created by the previous command. The layer created will be cached, and will be re-created only when changes are made.
/ We create a layer based on the contents of the file and then run NPM install, which means that unless we change package.json, Otherwise the next time we build Docker we will use NPM install to already run the cache layer and we don’t have to install all dependencies Docker builds every time we run them. This will save us a lot of time.
COPY.. looks at every file in our project directory, so this layer will rebuild as any files change (except package*.json). This is exactly what we want.
Building an application container
Let’s add a.dockerignore file, something like our.gitignore, because we don’t want to copy those files.
node_modules
npm-debug.log
Copy the code
With everything in place, we started building our own image,
# use the current project directory as the source directory and name the image qianduanwanjianke
$ docker build . -t qianduanwanjianke
Copy the code
Does the image we created exist?
With the image created, we are now ready to build a container from the image to run our application:
We gave the container a name, qianduanwanjianke-container
The # -p flag maps the port from port 3001 of our host (our computer) environment to port 8080 of the container environment, or of course 8080:8080.
docker run -p 3001:8080 --name qianduanwanjianke-container qianduanwanjianke
Copy the code
That’s it. Let’s go to http://localhost:3001/ and see if we succeeded,
conclusion
Here, we introduce Docker through a Node application, create our first custom Docker image and container, and run our application in it! This is a Docker introduction for Javascript developers, cut by the Node program, the content of the article for the backend developers familiar with Docker may be very easy, for our front-end developers should be a good introduction to the tutorial. Due to the long space, I decided to introduce Docker Volume(” connect “the application copy inside the container with the project directory copy, update synchronization) and introduce the database, analyze the difference between the database hosting server, how to create the separation, Docker Compose and other content in the next part.
Potholes in the process
Error during connect: This error may indicate that the docker daemon is not running…
Solutions:
# Improve access in Powershell to resolve this issue
cd "C:\Program Files\Docker\Docker"
./DockerCli.exe -SwitchDaemon
Copy the code
Docker build. -t my-node-app docker build. -t my-node-app No matching manifest for Windows/AMD64 10.0.18363 in the manifest list entries?
Solution: Open Docker Devlop, settiong -> Docker Engine, set experimental to true, and restart Docker