docker從入門到實戰-實戰篇
前言
本文是我通過三個星期業餘時間學習後而寫的文章,對docker的瞭解還處於入門階段。希望本文能幫忙一些想學習docker的朋友快速入門。練習及實戰代碼都在github倉庫中。如果我的文章能幫助到你的話,可以給我的docker項目點個贊哦
docker實戰
本次實戰案例是todolist。技術棧爲vue、node、mysql。具體代碼見項目目錄todolist,下面就不一一貼代碼了。就講下重點。
下面我就順着依賴關係來講,所以先從mysql開始講起
構建mysql
執行:docker run --name mymysql -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
- --name 給mysql容器設置匿名
- -d表示後臺運行
- -p表示將容器的3306端口的映射到本地的3308端口,如果不設置的話,本地是無法訪問該MySQL服務的。
- -e MYSQL_ROOT_PASSWORD 設置root的賬號密碼。
- mysql 後面不指定版本話,默認會latest版本
在執行該語句之前,假如你之前沒有pull過mysql鏡像。docker在本地找不到你要的鏡像就會幫你從docker倉庫拉取mysql:latest鏡像。
這個時候容器就啓動成功了。
嘗試下用navicat連接下試試
鼠標放入黃色小三角出現如下報錯。
2013 - Lost connection to MySQL server at 'reading initial communication packet', system error: 0 "Internal error/check (Not system error)"
這是因爲mysql8以上,都會使用新的驗證方式。
不妨查下信息: 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
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
plugin一欄可看到都是caching_sha2_password。
那麼如何才能將其改成可連接的呢?只需要將其plugin改成mysql_native_password就可以訪問了。
ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
你可以先用上面查詢賬戶信息查下是否修改成功了。
修改成功後,可以嘗試下用navicat連接下mysql。不出意外的話就能成功連接上了。
當然我下面的例子用mysql:5.6,方便操作,不需要修改plugin。
執行命令:docker run --name mymysql -d -e MYSQL_ROOT_PASSWORD=123456 -p 3308:3306 mysql:5.6
啓動容器後可以執行:docker exec -it mymysql bash
進入容器
執行:mysql -uroot -p123456
進入mysql控制檯
執行:show databases;
查看mysql數據庫
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
執行:create database todolist;
創建todolist應用的數據庫
執行:show databases;
查看剛剛創建的todolist數據庫
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| todolist |
+--------------------+
4 rows in set (0.00 sec)
可以看到數據庫中多了個todolist數據庫
接下來選擇該todolist數據庫
執行:use todolist;
選中該數據庫
創建表:
CREATE TABLE list (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
text VARCHAR(255),
checked INT(11) DEFAULT 0
);
執行:show tables;
查看todolist數據庫下的表
mysql> show tables;
+--------------------+
| Tables_in_todolist |
+--------------------+
| list |
+--------------------+
1 row in set (0.00 sec)
執行:describe list;
查看錶
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)
執行:insert into list set checked = 0, text = 'haha';
往表中插入一條數據;
執行:select * from list;
mysql> select * from list;
+----+------+---------+
| id | text | checked |
+----+------+---------+
| 1 | haha | 0 |
+----+------+---------+
1 row in set (0.01 sec)
一切正常
構建node
mysql服務啓動好了,接下來就是啓動node服務,並連接剛啓動的mysql服務了。
話不多說,直接上代碼,解釋看註釋
// index.js
const mysql = require('mysql'); // mysql包
const express = require('express');
const app = express();
const bodyParser = require('body-parser'); // post請求需要引入的包
app.use(bodyParser.json());
// mysql配置(用於連接剛啓動的mysql服務)
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 列表查詢
app.get('/getList', async (req, res) => {
const sql = `SELECT * FROM list`;
const data = await sqlFn(sql);
res.json({
code: 0,
data,
message: 'success'
})
})
// todolist 插入數據
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);
執行: node index.js
後,控制檯輸入
➜ server git:(master) ✗ node index.js
mysql connncted success!
表示node服務連接mysql服務成功;
瀏覽器可以訪問下localhost:3000/getList
{"code":0,"data":[{"id":1,"text":"haha","checked":0}],"message":"success"}
頁面將會出現剛纔我們sql插入到數據庫的數據
既然代碼沒有問題,那麼我們接下來就把他構建成鏡像。
構建之前需要把代碼中opt的host localhost改爲自己主機的ip。因爲容器啓動的話,連接mysql需要通過主機的3308端口訪問。
在當前文件夾新建名爲Dockerfile的文件
# 基於最新的 node 鏡像
FROM node:8
# 複製當前目錄下所有文件到目標鏡像 /app/ 目錄下
COPY . /todolist/server
# 修改工作目錄
WORKDIR /todolist/server
# 安裝依賴
RUN ["npm", "install"]
# 啓動 node server
ENTRYPOINT ["node", "index.js"]
執行:docker build -t mynode .
,生成node鏡像
- -t:表示給該鏡像添加版本,這裏不寫默認爲latest
可通過docker images
查看本地的鏡像。
➜ server git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mynode latest 3e8de2825063 4 seconds ago 898MB
可以看到第一個鏡像就是我們剛剛構建的鏡像
➜ server git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mynode latest 3e8de2825063 4 seconds ago 898MB
接下來運行基於這個鏡像的容器
執行:docker run --name mynode -d -p 4000:3000 mynode
- --name 給node容器起一個容器匿名
- -d 表示後臺運行
- -p 4000:3000 表示訪問本地4000代理容器內的3000端口服務
- mynode 是上面我們build構建的鏡像
啓動成功後,訪問下localhost:4000/getList
{"code":0,"data":[{"id":1,"text":"haha","checked":0}],"message":"success"}
可以看到頁面輸出我們上面執行sql語句插入的數據
上面貼的代碼只是基礎的查看列表與插入數據兩個方法,其他的請參考server
構建vue
todolist的靜態頁面,我是通過vue-cli3搭建的。
執行vue create app
創建項目。
進入項目根目錄執行npm run serve
頁面是否正常執行。
然後編寫簡易的具有增刪改查的todolist應用。具體代碼見todolist。
注意vue.config.js中的devServer配置的target: 'http://127.0.0.1:4000'代理到我們剛啓動的node容器
頁面啓動成功後,訪問localhost:8080
可以看到頁面加載成功,列表也成功渲染出上面構建mysql時,sql插入的數據。
本地啓動靜態並請求服務端成功後,接下來也將靜態頁面打包成鏡像,然後啓動靜態頁面容器
在打包鏡像容器之前,記得先將vue.config.js中的devServer配置的target: 'http://<主機ip地址>:4000'代理到我們剛啓動的node容器
編寫Dockerfile
# 基於最新的 node 鏡像
FROM node:8
# 複製當前目錄下所有文件到目標鏡像 /app/ 目錄下
COPY . /todolist/app
# 修改工作目錄
WORKDIR /todolist/app
RUN npm config set registry https://registry.npm.taobao.org && npm install
# RUN ["npm", "install"]
# 啓動 node server
ENTRYPOINT ["npm", "run", "serve"]
cd到靜態頁面的根目錄執行: docker build -t static .
執行:docker run --name static -d -p 9000:8080 static
啓動靜態容器
打開瀏覽器訪問localhost:9000
,可以看到頁面成功渲染出列表頁。
至此,mysql、node、vue容器均已互通。代碼需要完善的地方詳見todolist
docker-compose
我們不可能每次部署一個應用,需要手動啓動好幾個服務。這個時候就需要使用docker-compose
關於命令就不介紹了,這裏貼下鏈接
docker-compose命令
在根目錄下新建docker-compose.yml
配置文件
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
具體配置,詳見上面貼的鏈接。下面我介紹下我所寫的配置
- version: docker-compose的版本
- services: 代表你用docker-compose啓動的幾個服務
- build: 指定 Dockerfile 所在文件夾的路徑(可以是絕對路徑,或者相對 docker-compose.yml 文件的路徑)。 Compose 將會利用它自動構建這個鏡像,然後使用這個鏡像。
- container_name: 指定容器名稱。
- ports: 相當於docker run啓動容器的-p,<主機ip:容器ip>,這樣主機通過這個端口去訪問容器中的服務。
- environment: 只給定名稱的變量會自動獲取運行 Compose 主機上對應變量的值,可以用來防止泄露不必要的數據。簡而言之,就是在容器內可以獲取給的環境變量。
- depends_on: 解決容器的依賴、啓動先後的問題。(但是它有個問題就是隻是等所依賴的服務開啓啓動,並不是等依賴的服務啓動成功後在構建當前的服務。
- command: 覆蓋容器啓動後默認執行的命令
接下來解釋下上面用compose啓動的服務
值得一提的是,mysql的Dockerfile中做了創建數據庫與表的操作。會涉及到關閉數據庫密碼登錄功能。因爲關閉之後,操作數據庫就不需要輸入密碼了。等表建完之後在恢復密碼。
nodejs中的sleep.sh腳本是因爲depends_on這個依賴只是單純的等待其他服務開始啓動,並不是等待依賴的服務啓動完成之後纔開始構建自身的服務。這個時候node初始化會在mysql啓動完成之前啓動。這樣的話,node啓動的時候連接mysql就會報錯,導致node服務掛掉。所以引用了sleep.sh,讓node延遲一段時間啓動。
最後在docker-compose
文件所在的目錄下執行docker-compose build
再執行:docker-compose up
就可以啓動todolist這個應用的所有服務了。