Due to the word limit, can only be developed, connected to the above juejin.cn/post/690853…
Deployment
Docker uses static HTML files and nignx images to create and run a container, but it is much more than that. Let’s deploy this blog as an example to explore some of the knowledge inside.
Source code address: github.com/Moon-Future…
In order to maintain docker files uniformly, docker-related files will be placed under their respective directories under docker files below, so it is necessary to determine the context of topic construction.
1. Deploy the foreground blog
Port mapping 9000:9000. Server port: container port. If an online server is deployed, configure the corresponding port number in the security group
Create docker directory in blog directory, docker directory create three files
- .dockerignore: Ignore list of copied files
- Dockefile
- docker-compose.yml
.dockerignore
node_modules
.next
Copy the code
Dockefile
# node mirror
The # apline version of Node will be much smaller
FROM node:12-alpine
Create a directory in the container
RUN mkdir -p /usr/src/app
The following commands will be executed in the current directory
WORKDIR /usr/src/app
# copy package. Json
COPY package.json /usr/src/app
# install dependencies
RUN npm i --production --registry=https://registry.npm.taobao.org
# copy all other files to container (except directories and files in.dockerignore)
COPY . /usr/src/app
# build
RUN npm run build
Expose port 9000
EXPOSE 9000
Dokcerfile can only have one CMD command per file. If multiple, only the last one will be executed
CMD [ "npm"."start" ]
Copy the code
Docker images are layered, and the following points are important:
- Dockerfile in the mirror every instruction to create a new layer, each RUN is an instruction docs.docker.com/engine/refe…
- The image layer will be cached and reused
- When the Dockerfile directive is changed, the copied file is changed, or the variables specified when the image is built are different, the corresponding mirror layer cache is invalidated
- When a layer’s image cache is invalidated, all subsequent layer caches are invalidated
- The image layer is immutable, so if we add a file to one layer and then delete it from the next, the image will still contain the file (but the file is not visible in the Docker container).
So we first copy package.json, then RUN NPM I to install dependencies and form a mirror layer, then copy all other files to form a mirror layer, then if the code has changed but package.json has not changed, when executing again, no dependencies will be installed. It saves a lot of time. If package.json changes, RUN RUN I will be re-executed to install dependencies.
If the image generated, at this time to delete imageA, re-generate, remember Sir Into a new image imageB, so it will reuse the NPM package, if the first delete imageA, and then the new generation of imageB, it will reinstall the dependency.
To generate the image, run the following command in the blog directory: react_blog
$ docker build -f docker/Dockerfile . -t react_blog:blog
Copy the code
The first time you run the install dependency is a bit slow. When I first started using Node-sass, the installation was always wrong, but I switched to less. If you want to install yarn, the NPM related commands in Dockerfile can also be replaced with the appropriate YARN commands.
After a long wait for the build to succeed, the following information is the file generated by NPM run Build
Look at the resulting image
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE react_blog blog fef06dfed97f 3 minutes ago 329MB nginx latest ae2feff98a0c 31 hours Ago 133MB Node 12- Alpine 844F8bb6a3f8 3 weeks ago 89.7MBCopy the code
Then build and run the container
$ docker run -itd -p 9000:9000 --name react_blog_blog react_blog:blog
Copy the code
Here the parameters are explained again:
-i
The argument keeps the container’s standard input on, –interactive-t
The argument lets Docker assign a dummy terminal and bind it to the container’s standard input, –tty-d
–detach (Run container in background and print container ID)--name
Parameter Specifies a unique container name, or a random container name if not specified
– it generally and at the same time, the -d parameter, that is, if not add container operation success, will enter a terminal command interface, if you want to quit, Ctrl + C, only after exit containers also dropped out, docker ps – a can see container status is Exited (0). You can start it again using docker Start Container. Add -d and the container will run directly in the background, normally add -d. You can try it, and then delete the container.
If the above container is successfully executed, the page can be accessed from the browser using server IP :9000, or localhost:9000 for Mac or Windows.
docker-compose.yml
version: '3'
services:
web:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:blog
ports:
- 9000: 9000
container_name: react_blog_blog
Copy the code
Docker build, docker run and other commands are used to create containers, regenerate and run containers. The commands are not easy to remember and input. Here we can use docker-compose to simplify the execution of the command.
Let’s take a look at the document:
- Web: indicates the service name
- Build: Build related, to be executed later
docker-compose
The command path must be the same as docker-comemage. yml, so the context construction context selects the source directory of the previous layer, and dockerfile is the dockerfile in the current directory - Image: the name of the image. If there is an image, use it directly. If there is no image, use Dockerfile to generate it
- Ports: port mapping
- Container_name: specifies the name of the container, unique. If no, it is
Current directory _ Service name _index
Index number (summation from 1), if here isdocker_web_1
Docker rm -f react_blog_blog: compose up docker rm -f react_blog_blog: compose up docker rm -f react_blog_blog: compose up docker rm -f react_blog_blog: compose up docker-compose
Execute the command in the docker directory
$ docker-compose up -d
Copy the code
Docker-compose up -d –build can be used to regenerate the image
The above blog front-end page deployment, now just separate deployment learning, will be deleted and backend and interface deployment together.
2. Deploy the background admin
Port mapping 9001:9001: Server port: container port. If an online server is deployed, configure the corresponding port number in the security group
Now let’s deploy Admin separately. In Docker, we have already used Admin to simply deploy learning to make images and build containers. Here, we still first generate generate environment static files under the admin directory
$ npm run build
Copy the code
Create a docker directory under admin to store docker-related files. Create the following files under the docker directory:
Dockerfile
FROM nginx
# delete default configuration of Nginx
RUN rm /etc/nginx/conf.d/default.conf
EXPOSE 80
Copy the code
Notice some differences between here and above,
- The default configuration of nginx is removed here, and we will configure one ourselves
- There is no COPY of static files to the container in docker-comemage. yml by hanging them
docker-compose.yml
version: '3'
services:
admin:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:admin
ports:
- 9001: 80
volumes:
- ../build:/www
- ./nginx.conf:/etc/nginx/conf.d/nginx.conf
container_name: react_blog_admin
Copy the code
Volumes is an array of volumes that correspond to the host file in the container
- . /build:/ WWW, the files in build are hung in the container/WWW directory
- . / nginx. Conf: / etc/nginx/conf. D/nginx. Conf, nginx. Conf mounted to the container/etc/nginx/conf. D/nginx. Conf this file
The advantage of this is that when the files on the host are changed, the files in the container are automatically changed, and accordingly the files in the container are changed as well. In this way, after the source code changes and the build is repackaged, you only need to put it in the corresponding directory of the server, and the class capacity under the container class/WWW will be the latest, instead of executing the Dockerfile again and again to copy the build file into the container, and the database data is usually stored in the host. To prevent loss of data when the container is deleted.
The same applies to the nginx.conf configuration file, but after the nginx configuration file is changed, the following container needs to be restarted to take effect
To run the container, run the command in the docker directory
$ docker-compose up -d
Copy the code
Check whether the container runs successfully
$ docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7DB8CE1C6814 react_blog:admin "/ docker-entryPoint...." 16 minutes ago Up 16 minutes 0.0.0.0:9001->80/ TCP react_blog_adminCopy the code
Run docker logs container to view logs that fail
If successful, you can access the page from the browser using server IP :9001, Mac or Windows local localhost:9001.
nginx.conf
server {
listen 80;
sendfile on;
sendfile_max_chunk 1M;
tcp_nopush on;
gzip_static on;
location / {
root /www;
indexindex.html; }}Copy the code
Root remembers to hang in the same directory as above
3. Deploy the service interface service + Mysql
Port mapping 9002:9002: Server port: container port. If an online server is deployed, configure the corresponding port number in the security group
Create a docker directory under the service directory. Create the following files under the docker directory:
.dockerignore
node_modules
.github
article
Copy the code
The Article directory is used to house blog content files
Dockerfile
FROM node:alpine
Configure environment variables
ENV NODE_ENV production
This is the directory of the files in the container
RUN mkdir -p /usr/src/app
Set the working directory
WORKDIR /usr/src/app
# copy package.json file to working directory
#!!!!! Important: Package. json needs to be added separately.
# Docker builds the image layer by layer. Only when this layer changes, the corresponding layer will be rebuilt.
# If package.json is added to the image with the source code, the NPM module will need to be reinstalled every time the source code is modified, which is not necessary.
# So, the correct order is: add package.json; Install the NPM module. Add source code.
COPY package.json /usr/src/app/package.json
# Install NPM dependencies (using Taobao mirror source)
# If using an overseas server, there is no need to use taobao mirror source, that is, 'RUN NPM I'.
RUN npm i --production --registry=https://registry.npm.taobao.org
Copy all source code to the working folder
COPY . /usr/src/app
Expose the container port
EXPOSE 9002
CMD npm start
Copy the code
docker-compose.yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
depends_on:
- db
environment:
MYSQL_HOST: localhost
MYSQL_USER: root
MYSQL_PASSWORD: 8023
volumes:
- ../article:/usr/src/app/article
container_name: react_blog_service
db:
image: mysql
# volumes:
# - /db_data:/var/lib/mysql
ports:
- 33061: 3306
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: 8023
# MYSQL_USER: root
MYSQL_PASSWORD: 8023
MYSQL_DATABASE: react_blog
container_name: react_blog_mysql
Copy the code
Note that there are two services running: service and db
Service The service is the back-end interface:
-
Deponds_on: Run the services in the Deponds_on list first, in case the dependency is not yet run and it will report an error
-
Command: Starting with MySQL8.0, caching_sha2_password is used as the default encryption rule. This command can be used to change the encryption rule. Client does not support authentication protocol requested by server; consider upgrading MySQL client
-
/config/secret.js(secret-temp.js); /config/secret.js
/** * secret.js template */ module.exports = { // Mysql connection configuration mysql: { host: process.env.MYSQL_HOST || 'localhost'.port: process.env.MYSQL_PORT || '3306'.user: process.env.MYSQL_USER || 'xxx'.password: process.env.MYSQL_PASSWORD || 'xxx'.database: process.env.MYSQL_DATABASE || 'xxxxxx',},// jwt tokenConfig: { privateKey: 'xxxxxxxxxxxxxxxxxxxxxxxxx',}}Copy the code
-
Volumes: I’ve already written the post to the host and mounted it to the container
The db service is Mysql database:
-
Volumes: Data Settings are stored on the host
-
Ports: Port mapping, which allows the host to access Mysql inside the container through port 33061. We can then connect to it through Navicat or other database visualization tools
-
Environment: Configures the database
- MYSQL_ROOT_PASSWORD must be used to set the password of user ROOT
- MYSQL_USER MYSQL_USER;Pay attention toIf root is used, an error is reported
ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'%'
, according to theGithub.com/docker-libr…You can log in as user root by default. If you have a root account, you will create a new one - MYSQL_PASSWORD Specifies the password used by the container to log in to the Mysql database. If the user name is MYSQL_USER, the password is MYSQL_ROOT_PASSWORD. If the user name is ROOT, the new password is set
- MYSQL_DATABASE create a react_blog database, you can also create a container or Navicat database, but you need to connect to the react_blog database. (After the database is created, run both containers.)
Execute the command in the service/docker directory
$ docker-compose up -d
Copy the code
If it works, look at images and Containers
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE react_blog service 89139d833458 About an hour ago 150MB react_blog admin 1b5d6946f1fe 32 hours ago 133MB react_blog blog fef06dfed97f 35 hours ago 329MB nginx latest ae2feff98a0c 2 days ago 133MB mysql latest AB2F358b8612 6 days ago 545MB node 12- Alpine 844F8bb6a3F8 3 weeks ago 89.7MBCopy the code
You can see more Mysql and react_blog:blog mirrors
$ docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5878940d7626 react_blog:blog "docker..." 5 seconds ago Up 4 seconds 0.0.0.0:9000->9000/ TCP react_blog_blog 3bff0060de19 react_blog:admin "/docker..." 3 minutes ago Up 18 seconds 0.0.0.0:9001->80/ TCP react_blog_admin d8a899232e8c react_blog:service "docker..." About a Exited (1) 5 minutes ago react_blog_service a9DA07ff5cae mysql "docker..." About an hr 33060/ TCP, 0.0.0.0:33061->3306/ TCP react_blog_mysqlCopy the code
React_blog_service and react_blog_mysql failed to run. The react_blog_service failed to run
$ docker logs react_blog_service. Errno: "ECONNREFUSED" code: "ECONNREFUSED" syscall: "connect" address: "127.0.0.1" Port: 3306 fatal: true name: "ECONNREFUSEDError" pid: 47 hostname: d8a899232e8c ...Copy the code
Docker-comemage. yml: MYSQL_HOST=localhost; docker-comemage. yml: MYSQL_HOST=localhost; Localhost is the react_blog_service’s own IP (127.0.0.1), but it cannot access react_blog_mysql. We will address this problem in the next section, starting with Mysql.
The Mysql container is running successfully. We can access the container and connect to Mysql. Remember how to access the container
$ docker exec -it react_blog_mysql /bin/sh
$ ls
bin boot dev docker-entrypoint-initdb.d entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
$ mysql -uroot -pEnter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 12 Server version: 8.0.22 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help; ' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Copy the code
You can see that Mysql is connected successfully. Type exit to exit the container. We can also use visual tools to connect, in this case Navicat
Mysql > port 33061; port 33061; port 33061; port 33061;
Lost connection to Mysql server at ‘reading initial communication packet’ lost connection to Mysql server at ‘reading initial communication packet’ The solution is to run the systemctl start mysqld.service command to start the Mysql service. I don’t know where the Mysql service is affected, but LATER I will directly connect to the host Mysql without using containers, so that I can manage data in a unified way with other projects. My task is more convenient, and the data is safer.
4. Connect containers
The service failed to connect to the database. Refer to Docker Dream Builder series (I) : container interconnection
4.1 the Network type
A Network, as the name implies, enables different containers to communicate with each other. First of all, it is necessary to list the five drivers of Docker Network:
bridge
: The default driver mode, namely “bridge”, is usually usedstand-alone(To be more precise, a single Docker daemon)overlay
: Overlay network is used to connect multiple Docker daemonsThe clusterDocker Swarm will be highlighted in future articleshost
: Directly use the host (that is, the machine running Docker) network, only for Docker 17.06+ cluster servicemacvlan
: Macvlan Networks Allow each container to be displayed as a physical device by assigning a MAC address to it, suitable for applications (such as embedded systems, Internet of Things, and so on) that want to connect directly to a physical networknone
: Disables all networks for this container
By default, containers are created under the Bridge network, as shown below. Each container can connect to the HOST through dokcer0 and is assigned an IP address. In this case, containers need to enter each other’s IP address to connect to each other.
Viewing the Network List
$ docker network lsNETWORK ID NAME DRIVER SCOPE a75e040b03ed bridge bridge local 13545e6a3970 docker_default bridge local 5ec462838a1c host host local c726e6887f10 none null localCopy the code
There are 4 networks here, the default is only 3, there is no docker_default, I also write here to find that created a docker_default network, search the official website (Networking in Compose) found. Docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose: docker-compose Docker-comemage. yml is stored in the docker directory, so several containers are created in the docker_default network. You can view network details by following the command
$ docker network inspect docker_default[ { "Name": "docker_default", "Id": "13545e6a39708344b363b7fc16eefeb6775c37773222804ebd5b5fb6f28c38bb", "Created": 2020-12-16T11:03:37.2152073+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Default", "Options", null, "Config" : [{" Subnet configures ":" 172.24.0.0/16 ", "Gateway" : "172.24.0.1}]}," Internal ": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "23891d43187e046eea25936dc0ab703964cc6c7213bb150ae9529da3e2e57662": { "Name": "react_blog_mysql", "EndpointID": "649857f928e0444500cfd296035869678bf26162d429a4499b262776b2a1d264", "MacAddress": "02:42:ac:18:00:03", "IPv4Address": "" IPv6Address 172.24.0.3/16", ":" "}, "3 bff0060de19fc973039c07c1931e2c1efe30c6707bcd77d2ff7ea4dc01aaf63" : {" Name ": "react_blog_admin", "EndpointID": "25d8fa518b0ce27498f562372c3424aee174cb1d8fbf9f2445f1c6af8e6aab7f", "MacAddress": "02:42: ac: 18:00:02", "IPv4Address" : "172.24.0.2/16", "IPv6Address" : "" }, "5878940d7626a9fb20622cde4002075e390e5036036bafb99d80454d6cba594b": { "Name": "react_blog_blog", "EndpointID": "a3f8ee36eda09f524be7ea16a67a1e13e62cf558e5480218bb523f877d478e4a", "MacAddress": "02:42:ac:18:00:04", "IPv4Address": "" IPv6Address 172.24.0.4/16", ":" "}}, "Options" : {}, "Labels" : {" com.docker.compose.net work ": "Default", "com.docker.com pose. Project" : "docker", "com.docker.com pose. Version" : "1.25.1"}}]Copy the code
You can see that the docker_default gateway address is 172.24.0.1, and the other container IP addresses are 172.24.0.3, 172.24.0.2, and 172.24.0.4 respectively, so the situation here is like this
The default network bridge can only be connected to the container by entering the IP address, and the custom network can also be connected by the container name
On user-defined networks like
alpine-net
, containers can not only communicate by IP address, but can also resolve a container name to an IP address. This capability is called automatic service discovery.Networking with standalone containers
This avoids the problem of the container IP changing each time it is generated. /docker/ docker-comemage. yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
restart: on-failure
depends_on:
- db
environment:
MYSQL_HOST: react_blog_mysql # change localhost to mysql container name, in the same custom network, will automatically resolve to IP connection
MYSQL_USER: root
MYSQL_PASSWORD: 8023
volumes:
- ./article:/usr/src/app/article
container_name: react_blog_service
db:
image: mysql
ports:
- 33061: 3306
restart: on-failure
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: 8023
MYSQL_PASSWORD: 8023
MYSQL_DATABASE: react_blog
container_name: react_blog_mysql
Copy the code
Run the command here
$ docker-compose up -d --build
Copy the code
Docker logs react_blog_service does not return an error, indicating that the database has been connected. We have added a GET test interface in the code. In the browser input IP: 9002 / API/test/get or localhost: 9002 / API/test/get, returns a json object
{"message":"Hello You Got It"}
Copy the code
I’ve been trying this for a long time, I’ve been having problems,
-
ERROR 1396 (HY000): MYSQL_USER: root; Operation CREATE USER failed for ‘root’@’%’, according to github.com/docker-libr… You can log in as user root by default. If you have a root account, you will create a new one. Drop MYSQL_USER and use root to log in
-
Service docker start react_blog_service restart service docker start react_blog_service restart service docker start react_blog_service If you want to restart the service, you will not need to restart it. If you want to restart the service, you will not need to restart it. If you want to restart the service, you will not need to restart it.
Depends_on has been used. I am not sure why this issue exists, but the following is an example:
version: "3.9" services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres Copy the code
Depends_on does not wait for DB and Redis to be “ready” before starting web-only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
Depends_on does not wait for DB and Redis to be “ready” before starting Web – only before they start.
That should be the only reason
Let’s look at the docker_default network
$ docker network inspect docker_default[ { "Name": "docker_default", "Id": "13545e6a39708344b363b7fc16eefeb6775c37773222804ebd5b5fb6f28c38bb", "Created": 2020-12-16T11:03:37.2152073+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Default", "Options", null, "Config" : [{" Subnet configures ":" 172.24.0.0/16 ", "Gateway" : "172.24.0.1}]}," Internal ": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "3bff0060de19fc973039c07c1931e2c1efe30c6707bcd77d2ff7ea4dc01aaf63": { "Name": "react_blog_admin", "EndpointID": "25d8fa518b0ce27498f562372c3424aee174cb1d8fbf9f2445f1c6af8e6aab7f", "MacAddress": "02:42:ac:18:00:02", "IPv4Address": "" IPv6Address 172.24.0.2/16", ":" "}, "5878940 d7626a9fb20622cde4002075e390e5036036bafb99d80454d6cba594b" : {" Name ": "react_blog_blog", "EndpointID": "a3f8ee36eda09f524be7ea16a67a1e13e62cf558e5480218bb523f877d478e4a", "MacAddress": "02:42: ac: 18:00:04", "IPv4Address" : "172.24.0.4/16", "IPv6Address" : "" }, "83005eec8d50071a6c23a2be4af8552983c09c532e937f04d79f02f8eb68acc9": { "Name": "react_blog_mysql", "EndpointID": "265ed7793c98287a05ccf8997e81671287a02ee8ea464984996083a34abe10dd", "MacAddress": "02:42:ac:18:00:03", "IPv4Address": "" IPv6Address 172.24.0.3/16", ":" "}, "937339 a37ce726e704ec21b31b4028a97967a00de01438557e5a60d8538a51c8" : {" Name ": "react_blog_service", "EndpointID": "934d26f32a2b23e2cb4691020cb93d26c97b9647108047b492c3f7dd2be6faef", "MacAddress": "02:42: ac: 18:00:05", "IPv4Address" : "172.24.0.5/16", "IPv6Address" : ""}}," Options ": {}," Labels ": { "com.docker.compose.network": "default", "com.docker.compose.project": "docker", "com.docker.compose.version": "1.25.1"}}]Copy the code
React_blog_service has been added to the network. The IP address is 172.24.0.5
4.2 Customizing networks
Docker-comemess. yml files are stored in the docker directory, so they are all in the same network. If the name is changed, it will not be in the same network, and the project may also have a docker directory later. It’s not good to be all in one network, so here we are from the network that defines this project.
blog/docker/docker-compose.yml
version: '3'
services:
blog:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:blog
ports:
- 9000: 9000
networks:
- react_blog
container_name: react_blog_blog
networks:
react_blog:
Copy the code
admin/docker/docker-compose.yml
version: '3'
services:
admin:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:admin
ports:
- 9001: 80
volumes:
- ../build:/www
- ./nginx.conf:/etc/nginx/conf.d/nginx.conf
networks:
- react_blog
container_name: react_blog_admin
networks:
react_blog:
Copy the code
service/docker/docker-compose.yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
depends_on:
- db
environment:
- MYSQL_HOST=react_blog_mysql # change localhost to mysql container name, in the same custom network, will automatically resolve to IP connection
- MYSQL_USER=root
- MYSQL_PASSWORD=8023
volumes:
- ./article:/usr/src/app/article
networks:
- react_blog
container_name: react_blog_service
db:
image: mysql
ports:
- 33061: 3306
command: --default-authentication-plugin=mysql_native_password
environment:
- MYSQL_ROOT_PASSWORD=8023
- MYSQL_USER=root
- MYSQL_PASSWORD=8023
- MYSQL_DATABASE=react_blog
networks:
- react_blog
container_name: react_blog_mysql
networks:
react_blog:
Copy the code
- Networks of the same class as services: create a new network and add the directory name docker_react_blog to the network’s final name.
- React_blog (react_blog) react_blog (react_blog) react_blog (react_blog
Note:
In this way, all networks generated in docker-comemage. yml will be added with the current directory name. If you do not want to add the current directory name, you can create your own network
$ docker network create my_net
Copy the code
And then in docker-comemage.yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
depends_on:
- db
environment:
- MYSQL_HOST=react_blog_mysql # change localhost to mysql container name, in the same custom network, will automatically resolve to IP connection
- MYSQL_USER=root
- MYSQL_PASSWORD=8023
volumes:
- ./article:/usr/src/app/article
networks:
- my_net
container_name: react_blog_service
db:
image: mysql
ports:
- 33061: 3306
command: --default-authentication-plugin=mysql_native_password
environment:
- MYSQL_ROOT_PASSWORD=8023
- MYSQL_USER=root
- MYSQL_PASSWORD=8023
- MYSQL_DATABASE=react_blog
networks:
- my_net
container_name: react_blog_mysql
networks:
my_net:
external: true
Copy the code
External will use the network already created (my_net) without creating or adding the directory name.
Let’s recreate the container, first deleting all containers
$ docker stop $(docker ps -aq)
$ docker rm $(docker ps -aq)
Copy the code
Docker-compose up -d: Creating network “docker_react_blog” with the default driver: docker-compose up -d: Creating network “docker_react_blog” with the default driver A new network has been created
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a75e040b03ed bridge bridge local
13545e6a3970 docker_default bridge local
e1ceb437a4fd docker_react_blog bridge local
5ec462838a1c host host local
c726e6887f10 none null local
$ docker network inspect docker_react_blog[ { "Name": "docker_react_blog", "Id": "e1ceb437a4fdc5de91e51ff8831e21b565c92754159ad7057de36758e548a92f", "Created": "2020-12-19T01:39:02.201644444+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Default", "Options", null, "Config" : [{" Subnet configures ":" 172.18.0.0/16 ", "Gateway" : "172.18.0.1}]}," Internal ": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "00da404f6f050b9b2f20e39bbb136fef614e8dfee85ec31bd6000bfd59cc2dab": { "Name": "react_blog_mysql", "EndpointID": "1cb966cc731eca3e9721e6d3edcfcac6152b66051faa934557f567e9e36c75c6", "MacAddress": "02:42:ac:12:00:04", "IPv4Address": "" IPv6Address 172.18.0.4/16", ":" "}, "ad1480e48e8e7ed160b1d4bcf7eed77d74505aea7581d48d8931206772b5d805" : {" Name ": "react_blog_service", "EndpointID": "8866c3457382d6baa945da09aef40da54c7dfdea0f393485001c35bb37d201a0", "MacAddress": "02:42: ac: 12:00:05", "IPv4Address" : "172.18.0.5/16", "IPv6Address" : "" }, "b518d40b5021d3fdec7b7e62fbaa47b8a705a38346ccba2b9814174e46b67cd0": { "Name": "react_blog_admin", "EndpointID": "9a58ff20dc57d4d1fa6af83482051a68e80e22a5e37cf8e0cb3570b78102f107", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "" IPv6Address 172.18.0.3/16", ":" "}, "db0050257a8e8a0fa430ea04b009ae819dbf04ef001cf1027ec2b5565403b48e" : {" Name ": "react_blog_blog", "EndpointID": "664794ed292871bc7fd8e1c4eaa56f682a6be5d653209f84158f3334a4f30660", "MacAddress": "02:42: ac: 12:00:02", "IPv4Address" : "172.18.0.2/16", "IPv6Address" : ""}}," Options ": {}," Labels ": { "com.docker.compose.network": "react_blog", "com.docker.compose.project": "docker", "com.docker.compose.version": "1.25.1"}}]Copy the code
4.3 Calling An Interface
There is a problem, now we call interface in the code form is http://localhost:9002/api/xxx, call interface in react_blog_blog container localhost is itself, The interface in react_blog_service is not called.
In view of the admin
In the code, we call the interface like this
const HOST = process.env.NODE_ENV === 'development' ? 'http://localhost:9002' : ' '
const API = {
getArticleList: HOST + '/api/getArticleList'.getArticle: HOST + '/api/getArticle'.addArticle: HOST + '/api/addArticle'.delArticle: HOST + '/api/delArticle'.getTagList: HOST + '/api/getTagList'.addTag: HOST + '/api/addTag'.delTag: HOST + '/api/delTag'.register: HOST + '/api/register'.login: HOST + '/api/login',}export default API
Copy the code
You’ll find interface 404, which we proxy through nginx
admin/docker/nginx.conf
server {
listen 80;
sendfile on;
sendfile_max_chunk 1M;
tcp_nopush on;
gzip_static on;
location /api {
proxy_pass http://react_blog_service:9002;
}
location / {
root /www;
indexindex.html; }}Copy the code
For requests that start with/API, we forward them to the 9002 port of the react_blog_service container and drag nginx.conf to the server. Since we are mounting this file inside the container, we just need to restart the container
$ docker restart react_blog_admin
Copy the code
React_blog.sql (); / / react_blog.sql (); / / react_blog.sql (); / / react_blog.sql ()
In view of the blog
I thought through the environment variable (Next to be stored in the variable at Runtime Runtime Configuration) request to transfer the HOST (react_blog_service | | localhost). React_blog_service was not supported by the front-end interface (getServerSideProps was), so nginx was used to proxy the request. And we definitely needed to use the domain name to access the site, so we still needed nginx. So let’s add an Nginx container for the foreground page.
1. Create environment variables
blog/docker/Dockerfile
# node mirror
The # apline version of Node will be much smaller
FROM node:12-alpine
Create a directory in the container
RUN mkdir -p /usr/src/app
The following commands will be executed in the current directory
WORKDIR /usr/src/app
# copy package. Json
COPY package.json /usr/src/app
# install dependencies
RUN npm i --production --registry=https://registry.npm.taobao.org
# copy all other files to container (except directories and files in.dockerignore)
COPY . /usr/src/app
# Build phase capture
ENV HOST react_blog_service ## Add an environment variable, available during the build phase, that must precede the NPM run build line
# build
RUN npm run build
Expose port 9000
EXPOSE 9000
Dokcerfile can only have one CMD command per file. If multiple, only the last one will be executed
CMD [ "npm"."start" ]
Copy the code
In the code, the setup run is the variable blog/ next-config.js
const withCSS = require('@zeit/next-css')
const withLess = require('@zeit/next-less')
module.exports = () = >withLess({ ... withCSS(),// Change to nginx proxy
publicRuntimeConfig: {
HOST: process.env.HOST || 'localhost'.// If it is a docker build, run process.env.host, otherwise run localhsot}})Copy the code
In the blog/config/API
import getConfig from 'next/config'
const { publicRuntimeConfig } = getConfig()
const SSRHOST = `http://${publicRuntimeConfig.HOST}: 9002 `
const HOST = `http://localhost:9002`
export const SSRAPI = {
getArticleList: SSRHOST + '/api/getArticleList'.getArticle: SSRHOST + '/api/getArticle',}export const API = {
getArticleList: HOST + '/api/getArticleList'.getArticle: HOST + '/api/getArticle',}Copy the code
There’s a little bit of trouble here, I don’t know if I’m getting this right, but I’ve tried a lot of things and only this local and Docker deployment works.
-
If it is run locally (without docker), the server obtains the data (getServerSideProps) and the page obtains the data directly using the service interface address (localhost:9002)
-
If docker is running, the server needs to directly bring the address of the service interface container (getServerSideProps), not through the nginx proxy. If the page gets the data, the function is through the nginx proxy
2. Nginx proxy
Modify blog/docker/ docker-comemage. yml to add an nginx container
version: '3'
services:
blog:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:blog
# ports:
# - 9000:9000
networks:
- react_blog
container_name: react_blog_blog
nginx:
build:
context: ../
dockerfile: ./docker/Dockerfile-nginx
image: react_blog:nginx
ports:
- 9000: 80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/nginx.conf
networks:
- react_blog
container_name: react_blog_nginx
networks:
react_blog:
Copy the code
blog/docker/Dockerfile-nginx
FROM nginx
# delete default configuration of Nginx
RUN rm /etc/nginx/conf.d/default.conf
EXPOSE 80
Copy the code
blog/docker/nginx.conf
server {
listen 80;
sendfile on;
sendfile_max_chunk 1M;
tcp_nopush on;
gzip_static on;
location /api {
proxy_pass http://react_blog_service:9002;
}
location / {
proxy_passhttp://react_blog_blog:9000; }}Copy the code
3. Build containers
Docker-compose up -d –build will re-download NPM node_modules. Docker-compose up -d –build will re-download NPM node_modules.
Execute in the blog directory
$ docker build -f docker/Dockerfile . -t react_blog:blog
Copy the code
Execute under blog/docker
$ docker-compose up -d
Copy the code
If successful, try the interface again to get the data.
5. Connect to the host Mysql
I encountered a problem with Mysql on my server (host). Lost connection to mysql server at ‘reading initial communication packet’ 2013 lost connection to mysql server at ‘reading initial communication packet’ The systemctl start mysqld.service command is used to start the Mysql service. Because other projects were deployed separately before, without using Docker, and the data were all on the host Mysql, I still prefer unified management and adaptive host Mysql. Let’s see how to implement it.
There are two ways to do this
Mode 1: network_mode: host
Modify the service/docker docker – compose. Yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
restart: on-failure
# depends_on:
# - db
environment:
# MYSQL_HOST: react_blog_mysql
MYSQL_USER: root
MYSQL_PASSWORD: 8023
volumes:
- ../article:/usr/src/app/article
network_mode: host
# networks:
# - react_blog
container_name: react_blog_service
# db:
# image: mysql
# ports:
# - 33061:3306
# restart: on-failure
# command: --default-authentication-plugin=mysql_native_password
# environment:
# MYSQL_ROOT_PASSWORD: 8023
# MYSQL_PASSWORD: 8023
# MYSQL_DATABASE: react_blog
# networks:
# - react_blog
# container_name: react_blog_mysql
networks:
react_blog:
Copy the code
Service /docker to execute the command
$ docker-compose up -d
$ docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES AF9e525e7d14 react_blog:service "docker-entryPoint.s..." 28 seconds ago Up 26 seconds react_blog_serviceCopy the code
Docker inspect react_blog_service does not assign IP. This is equivalent to a Node application connecting itself to the host Mysql. But for page interface requests, because react_blog_service is no longer in docker_react_blog, it is accessed using the host IP address.
nginx.conf
server {
listen 80;
sendfile on;
sendfile_max_chunk 1M;
tcp_nopush on;
gzip_static on;
location /api {
# proxy_pass http://react_blog_service:9002;
proxy_pass http://xxx.xx.xxx.x:9002; # xxx.xx.xxx.x is the IP address of the host
}
location / {
proxy_passhttp://react_blog_blog:9000; }}Copy the code
The same is true of the server-side render interface
# node mirror
The # apline version of Node will be much smaller
FROM node:12-alpine
Create a directory in the container
RUN mkdir -p /usr/src/app
The following commands will be executed in the current directory
WORKDIR /usr/src/app
# copy package. Json
COPY package.json /usr/src/app
# install dependencies
RUN npm i --production --registry=https://registry.npm.taobao.org
# copy all other files to container (except directories and files in.dockerignore)
COPY . /usr/src/app
# build phase, xxx.xx.xxx.x is the host (server)IP
ENV HOST xxx.xx.xxx.x
# build
RUN npm run build
Expose port 9000
EXPOSE 9000
Dokcerfile can only have one CMD command per file. If multiple, only the last one will be executed
CMD [ "npm"."start" ]
Copy the code
This way is not very troublesome, but also expose the server IP address, so I choose the second way
Method 2:
Modify the service/docker docker – compose. Yml
version: '3'
services:
service:
build:
context: ../
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
restart: on-failure
# depends_on:
# - db
environment:
MYSQL_HOST: 172.17. 01.
MYSQL_USER: root
MYSQL_PASSWORD: 8023
volumes:
- ../article:/usr/src/app/article
networks:
- react_blog
container_name: react_blog_service
# db:
# image: mysql
# ports:
# - 33061:3306
# restart: on-failure
# command: --default-authentication-plugin=mysql_native_password
# environment:
# MYSQL_ROOT_PASSWORD: 8023
# MYSQL_PASSWORD: 8023
# MYSQL_DATABASE: react_blog
# networks:
# - react_blog
# container_name: react_blog_mysql
networks:
react_blog:
Copy the code
MYSQL_HOST is 172.17.0.1. The container can connect to the host using this IP address, so it connects to the host’s Mysql database.
6. A docker – compoer. Yml
Docker-composing. Yml: docker-composing. Yml: docker-composing. Yml: docker-composing
Create docker/ docker-comemage. yml in the project root directory to create a docker directory, in order to create a network and a single project run is created consistent
version: '3'
services:
blog:
build:
context: ../blog
dockerfile: ./docker/Dockerfile
image: react_blog:blog
networks:
- react_blog
container_name: react_blog_blog
nginx:
build:
context: ../blog
dockerfile: ./docker/Dockerfile-nginx
image: react_blog:nginx
ports:
- 9000: 80
volumes:
- ../blog/docker/nginx.conf:/etc/nginx/conf.d/nginx.conf
networks:
- react_blog
container_name: react_blog_nginx
admin:
build:
context: ../admin
dockerfile: ./docker/Dockerfile
image: react_blog:admin
ports:
- 9001: 80
volumes:
- ../admin/build:/www
- ../admin/docker/nginx.conf:/etc/nginx/conf.d/nginx.conf
networks:
- react_blog
container_name: react_blog_admin
service:
build:
context: ../service
dockerfile: ./docker/Dockerfile
image: react_blog:service
ports:
- 9002: 9002
restart: on-failure
environment:
MYSQL_HOST: 172.17. 01.
MYSQL_USER: root
MYSQL_PASSWORD: 8023
volumes:
- ../service/article:/usr/src/app/article
networks:
- react_blog
container_name: react_blog_service
networks:
react_blog:
Copy the code
Stop and delete all containers created previously
$ docker stop $(docker ps -aq)
$ docker rm $(docker ps -aq)
Copy the code
Go to the /docker directory and execute,
$ docker-compose up -d
Building nginx
Step 1/3 : FROM nginx
---> ae2feff98a0c
Step 2/3 : RUN rm /etc/nginx/conf.d/default.conf
---> Running in bb163c42c6b5
Removing intermediate container bb163c42c6b5
---> 282cb303dddf
Step 3/3 : EXPOSE 80
---> Running in 9b77ebd39952
Removing intermediate container 9b77ebd39952
---> fbb18dda70af
Successfully built fbb18dda70af
Successfully tagged react_blog:nginx
WARNING: Image for service nginx was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Building admin
Step 1/3 : FROM nginx
---> ae2feff98a0c
Step 2/3 : RUN rm /etc/nginx/conf.d/default.conf
---> Using cache
---> 282cb303dddf
Step 3/3 : EXPOSE 80
---> Using cache
---> fbb18dda70af
Successfully built fbb18dda70af
Successfully tagged react_blog:admin
WARNING: Image for service admin was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating react_blog_admin ... done
Creating react_blog_service ... done
Creating react_blog_blog ... done
Creating react_blog_nginx ... done
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1fbb15abdd30 react_blog:service "docker" 13 seconds ago Up 6 seconds 0.0.0.0:9002->9002/tcp react_blog_service
fbee53e25c3a react_blog:admin "/docker" 13 seconds ago Up 6 seconds 0.0.0.0:9001->80/tcp react_blog_admin
70cb25f87d14 react_blog:blog "docker" 13 seconds ago Up 6 seconds 9000/tcp react_blog_blog
aa9fbf2afea4 react_blog:nginx "/docker" 13 seconds ago Up 6 seconds 0.0.0.0:9000->80/tcp react_blog_nginx
Copy the code
Running successfully ~
7. The domain name
I am now using the host’s nginx to proxy the domain name to IP:9000, and then to the react_blog_nginx container, trying to proxy directly in react_blog_nginx, but failed. React_blog_nginx is accessed through port mapping, host IP:9000. If you configure the domain name inside react_blog_nginx, it will always feel impossible to access it.
conclusion
Before finally finished writing, writing has been learning to try for a long time, thought is very sure, results in the process of writing and a pile of problems, a problem will probably card day for a long time, all kinds of baidu, Google, using tubing, finally solved all the problems, of course, these problems can only meet the demand of the deployment I now, there were a lot of knowledge, No, but that’s okay, I just want to successfully deploy the front-end project.
The above are all the notes of docker deployment front-end project, the content is rather wordy, I hope to help the later students to make less mistakes, because some of them are their own understanding, there may be mistakes, please correct, learn from each other, over.