docker從入門到實戰-實戰篇

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這個應用的所有服務了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章