Preface
This is an article I wrote after three weeks of spare time study. My understanding of docker is still at the beginning stage. I hope this article can help some friends who want to learn docker get started quickly. The exercises and actual combat codes are in the github repository. If my article can help you, you can give it to me. docker project Give me a compliment.
Doker Actual Warfare
The actual combat case is todolist. The technology stack is vue, node and mysql. See the project directory for the specific code todolist Next, I will not post code one by one. Let's talk about the key points.
Now I'm going to talk about dependencies, so let's start with mysql.
Constructing mysql
Execution: docker run -- name mymysql-d-p 3308:3306-e MYSQL_ROOT_PASSWORD = 123456 MySQL
- - name anonymizes mysql container
- - d denotes background operation
- - p means mapping the port 3306 of the container to the local port 3308. If not set, the MySQL service cannot be accessed locally.
- - e MYSQL_ROOT_PASSWORD sets the root account password.
- If no version is specified after mysql, the latest version will be defaulted.
Before executing this statement, suppose you haven't pulled the MySQL image before. If docker can't find the image you want locally, it will pull the mysql:latest image from the docker warehouse.
Then the container starts up successfully.
Try connecting with navicat
The following error occurred when the mouse was placed in the small yellow triangle.
2013 - Lost connection to MySQL server at 'reading initial communication packet', system error: 0 "Internal error/check (Not system error)"
This is because mysql8 or more will use new authentication methods.
Check out the information: select host,user,plugin,authentication_string from mysql.user;
mysql> select host,user,plugin,authentication_string from mysql.user; +-----------+------------------+-----------------------+------------------------------------------------------------------------+ | host | user | plugin | authentication_string | +-----------+------------------+-----------------------+------------------------------------------------------------------------+ | % | root | caching_sha2_password | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | | localhost | mysql.infoschema | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | | localhost | mysql.session | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | | localhost | mysql.sys | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | )7k44VulAglQJgGpvgSG.ylA/rdbkqWjiqQJiq3DGsug5HIy3 |ord | $A$005$0pU+sGm[on +-----------+------------------+-----------------------+------------------------------------------------------------------------+
The plugin column shows caching_sha2_password.
So how can we change it to connectable? Just change its plugin to mysql_native_password to access it.
ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
You can check the account information above to see if the modification is successful.
After the modification is successful, you can try to connect mysql with navicat. It can be connected successfully without any accident.
Of course, my following example uses mysql:5.6, which is easy to operate without modifying the plugin.
Execute the command: docker run -- name mymysql-d-e MYSQL_ROOT_PASSWORD = 123456-p 3308:3306 mysql:5.6
After starting the container, it can be executed: docker exec-it MySQL bash enters the container
Execution: mysql-uroot-p123456 enters MySQL console
Execution: show databases; view mysql database
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+ 3 rows in set (0.00 sec)
Execution: create database to dolist; create database to dolist application
Execution: show databases; view the todolist database just created
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | todolist | +--------------------+ 4 rows in set (0.00 sec)
You can see that there are more todolist databases in the database.
Next, select the todolist database
Execution: use to dolist; select the database
Create tables:
CREATE TABLE list ( id INT(11) AUTO_INCREMENT PRIMARY KEY, text VARCHAR(255), checked INT(11) DEFAULT 0 );
Execution: show tables; view tables under the todolist database
mysql> show tables; +--------------------+ | Tables_in_todolist | +--------------------+ | list | +--------------------+ 1 row in set (0.00 sec)
Execution: describe list; view table
mysql> describe list; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | text | varchar(255) | YES | | NULL | | | checked | int(11) | YES | | 0 | | +---------+--------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec)
Execution: insert into list set checked = 0, text ='haha'; insert a data into the table;
Execution: select * from list;
mysql> select * from list; +----+------+---------+ | id | text | checked | +----+------+---------+ | 1 | haha | 0 | +----+------+---------+ 1 row in set (0.01 sec)
Business as usual
Building node
The mysql service is started, and the next step is to start the node service and connect to the newly started mysql service.
Don't say much, just go to the code, explain and see the comments.
// index.js const mysql = require('mysql'); // mysql package const express = require('express'); const app = express(); const bodyParser = require('body-parser'); // Packets to be introduced for post requests app.use(bodyParser.json()); // mysql configuration (for connecting to the newly started mysql service) const opt = { host: 'localhost', user: 'root', port: '3308', password: '123456', database: 'todolist' }; const connection = mysql.createConnection(opt); const sqlFn = (sql) => { return new Promise((resolve, reject) => { connection.query(sql, (err, results, filelds) => { if (err) throw err; resolve(results); }); }) } connection.connect(async (err) => { if (err) throw err; console.log('mysql connncted success!'); }) // todolist list list list query app.get('/getList', async (req, res) => { const sql = `SELECT * FROM list`; const data = await sqlFn(sql); res.json({ code: 0, data, message: 'success' }) }) // todolist inserts data app.post('/insert', async (req, res) => { const sql = `INSERT INTO list SET checked = ${req.body.checked}, text = '${req.body.text}'`; const data = await sqlFn(sql); res.json({ code: 0, data, message: 'success' }) }) app.listen(3000);
Execution: After node index.js, console input
➜ server git:(master) ✗ node index.js mysql connncted success!
Represents the success of connection of node service to mysql service.
Browsers can access localhost:3000/getList
{"code":0,"data":[{"id":1,"text":"haha","checked":0}],"message":"success"}
The page will display the data we just inserted into the database with sql
Now that the code is okay, let's build it into a mirror.
Before building, you need to change the host localhost of opt in your code to the ip of your host. Because if the container starts, connecting mysql needs to be accessed through port 338 of the host.
Create a new file named Dockerfile in the current folder
# Based on the latest node image FROM node:8 # Copy all files in the current directory to the target image/app/directory COPY . /todolist/server # Modify working directory WORKDIR /todolist/server # Installation dependency RUN ["npm", "install"] # Start node server ENTRYPOINT ["node", "index.js"]
Execution: docker build-t mynode., generate node image
- - t: Represents adding a version to the image, instead of the default latest
The local image can be viewed through docker images.
➜ server git:(master) ✗ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynode latest 3e8de2825063 4 seconds ago 898MB
The first image you can see is the one we just built.
➜ server git:(master) ✗ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynode latest 3e8de2825063 4 seconds ago 898MB
Next, run the container based on this image
Execution: docker run -- name mynode-d-p 4000:3000 mynode
- - name gives node container an anonymity
- - d denotes background operation
- - p 4000:3000 represents access to 3000 port services within the local 4000 proxy container
- mynode is the mirror we built above
After successful startup, access the localhost:4000/getList
{"code":0,"data":[{"id":1,"text":"haha","checked":0}],"message":"success"}
You can see that the page outputs the data that we inserted in the sql statement above.
The code posted above is just the basic way to view lists and insert data. For others, please refer to it. server
Building vue
The static page of todolist is built by vue-cli3.
Execute vue create app to create the project.
Enter the project root directory to execute the NPM run server page.
Then write a simple todolist application with addition, deletion and modification. See Specific Code todolist.
Note the target of devServer configuration in vue.config.js: ' http://127.0.0.1 4 000'proxy to our newly launched node container
After the page starts successfully, visit localhost:8080
You can see that the page was loaded successfully and the list successfully rendered the data that sql inserted when mysql was built above.
After starting the static locally and requesting the server to succeed, the static page is then packaged into a mirror and the static page container is started.
Before packaging the mirror container, remember to configure the target of devServer configuration in vue.config.js: ' http://< Host ip address >: 4000'proxy to our newly launched node container
Writing Dockerfile
# Based on the latest node image FROM node:8 # Copy all files in the current directory to the target image/app/directory COPY . /todolist/app # Modify working directory WORKDIR /todolist/app RUN npm config set registry https://registry.npm.taobao.org && npm install # RUN ["npm", "install"] # Start node server ENTRYPOINT ["npm", "run", "serve"]
cd to static page root directory execution: docker build-t static.
Execution: docker run -- name static-d-p 9000:8080 static start static container
Open the browser to visit localhost:9000, and you can see that the page successfully renders the list page.
So far, mysql, node, vue containers have been interoperable. See the code for details todolist
docker-compose
We can't deploy one application at a time. We need to start several services manually. This is the time to use docker-compose
There is no introduction to commands. Here is a link.
docker-compose command
Create a new docker-compose.yml configuration file in the root directory
version: '2' services: static: build: ./app/ container_name: static ports: - 7001:8080 depends_on: - nodejs - db nodejs: build: context: ./server/ dockerfile: sleep-dockerfile container_name: nodejs ports: - 4000:3000 environment: - IS_START_BY_COMPOSE=1 command: sh ./sleep.sh depends_on: - db db: image: mysql:5.6 container_name: db environment: MYSQL_ROOT_PASSWORD: "123456" command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4
Detailed configuration, see the link posted above. Now let me introduce the configuration I have written.
- version: docker-compose version
- Services: Several services started on behalf of you with docker-compose
- Build: Specifies the path of the folder where the Dockerfile is located (either absolute or relative to the docker-compose.yml file). Compose will use it to automatically build the image and then use it.
- container_name: Specifies the container name.
- ports: The equivalent of docker run to start the container - p, <host ip: container ip>, so that the host accesses the service in the container through this port.
- environment: Variables with a given name automatically get the value of the strain on the running Compose host, which can be used to prevent unnecessary data from being leaked. In short, it is the environmental variables that can be obtained in the container.
- Dependent_on: Solve the problem of container dependence and start-up sequence. (But it has a problem that it just waits for the dependent services to start, not to build the current services after the dependent services start successfully.
- command: Overrides commands that are executed by default after the container is started
Next, explain the services started with compose above.
It is worth mentioning that the operation of creating database and table is done in Dockerfile of mysql. It involves closing the database password login function. Because after closing, you don't need to enter a password to operate the database. After the table is built, the password is restored.
The sleep.sh script in nodejs is because depend_on is a dependency that simply waits for other services to start, not for the dependent services to start building their own services after they are started. Node initialization will start before mysql starts. In this way, the connection to mysql at node startup will report an error, causing the node service to hang up. So sleep.sh is referenced to delay the start of node for a period of time.
Finally, the docker-compose build is executed in the directory where the docker-compose file resides.
Re-execution: docker-compose up can start all the services of the todolist application.