誰說前端不用懂,手摸手 Docker 從入門到實踐
本文轉載自微信公眾號「前端下午茶」,作者SHERlocked93。轉載本文請聯系前端下午茶公眾號。
在下最近遇到要在服務器上安裝 Mysql、Nginx、EasyMock 等工具的場景,這里記錄一下我使用 Docker 安裝的過程,希望也能在類似的場景中幫助到大家~
- CentOS 版本:7.6
- Nginx 版本:1.16.1
- Docker 版本:19.03.12
你多學一樣本事,就少說一句求人的話
1. 介紹
1.1 出現的原因
前后端開發到測試到生產的過程中,經常會遇到一個問題,明明我在本地跑沒問題,為什么到測試環境或者生產環境就報錯了了呢,常常這是因為開發、測試、生產的環境與配置不同導致的。
折騰過環境配置的人都明白其中麻煩,換一臺系統、虛擬機、機器,就又要重來一次,費力費時。由于環境和配置的原因,各種奇奇怪怪因為環境和配置的 Bug,總是像打地鼠游戲里面的地鼠一樣不斷冒出來 ??
Docker
Docker 對這個問題給出了一個很好的解決方案,通過鏡像將除了系統之外所需要的系統環境由下而上打包,達到服務跨平臺的無縫運作。也就是說,安裝的時候,把特定的環境一模一樣地搬過來,從而解決「在我的電腦上能跑,在 xx 環境就跑不了」的情況。
另外一個重要的原因,就是輕量,基于容器的虛擬化,Docker 的鏡像僅包含業務運行所需的 runtime 環境,一個 CentOS/Ubuntu 基礎鏡像僅 170M,因為輕量一個宿主機可以輕松安裝數百個容器。
1.2 是什么
Docker 是基于 Go 語言實現的云開源項目,從 2013 年發布到現在一直廣受關注。Docker 可以讓你像使用集裝箱一樣快速的組合成應用,并且可以像運輸標準集裝箱一樣,盡可能的屏蔽代碼層面的差異。它將應用程序與該程序的依賴,打包在一個文件里面。運行這個文件,就會生成一個虛擬容器。
程序在這個虛擬容器里運行,就好像在真實的物理機上運行一樣。有了 Docker,就不用擔心環境問題。
本文就不對比虛擬機跟 Docker 的區別和優劣了,每個文章都有,說爛了,想了解的話可以百度一下 ??,我這里就不多說了,下面直接看看怎么安裝怎么用起來吧。
2. 安裝 & 配置
2.1 Mac 下安裝
在下直接使用 Homebrew Cask 來安裝,Mac 下:
- # Homebrew 安裝
- $ braw cask install docke
即可,安裝完輸入命令,直接報錯!
- ➜ ~ docke
- zsh: command not found: docker # 報錯
遇到這個報錯別擔心,安裝完之后要在應用列表里面雙擊 Docker 應用,輸入密碼之后就可以使用這個命令了 ??。
2.2 CentOS 下安裝
Docker 要求 CentOS 版本必須在 6.5 及以上才可以安裝。
- # 安裝
- $ sudo yum install yum-utils device-mapper-persistent-data lvm2
- $ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
- $ sudo yum install docker-ce
- # 開啟 Docke
- $ sudo systemctl start docke
在 Windows 上可以直接下載安裝包來安裝,或者 Mac 上不使用 Homebrew 也可以去官網直接下載安裝包來安裝,百度一下到處都是安裝方法,其他的就不用多說。
3. 簡單配置并跑起來
3.1 配置鏡像加速
在 MacOS 的 Docker 配置 Perferences -> Docker Engine 或者 Windows 的 Settings -> Deamon 中的 JSON 中增加一項 registry-mirrors 如下
Docker鏡像加速配置
配置完之后在命令行中 docker info 就可以查看到我們配置的鏡像加速地址了。
- ➜ ~ sudo docker info
- ...
- Registry Mirrors:
- https://reg-mirror.qiniu.com/
- http://hub-mirror.c.163.com/
- https://registry.docker-cn.com/
- ...
如果你的系統的 Docker 沒有客戶端,比如 CentOS 中,可以直接修改 deamon 配置文件:
- # 修改/創建 docker 的 deamon 配置文件
- $ sudo vi /etc/docker/daemon.json
- # 修改為如下配置
- {
- "experimental": false,
- "debug": true,
- "registry-mirrors": [
- "https://reg-mirror.qiniu.com",
- "http://hub-mirror.c.163.com",
- "https://registry.docker-cn.com"
- ]
- }
- # 修改完 :wq 重啟
- $ sudo systemctl restart docke
3.2 Hello World !
然后就可以快樂跑起來我們第一個 Docker 指令 Hello World 了
Docker跑起Helloworld
Good start !
4. 鏡像 & 容器 & 倉庫
鏡像和容器的關系就像類和類的實例,一個鏡像可以同時跑多個容器,單個容器實例又可以創建新的鏡像。如下圖:
鏡像容器倉庫
下面解釋一下這個圖里面出現的元素
| 概念 | 說明 |
|---|---|
| Docker 鏡像 Images | 用于創建 Docker 容器的只讀模板,比如 Ubuntu 16.04系統、Nginx 1.16.0 等,是一個特殊的文件系統,包括容器運行時需要的程序、庫、資源、參數等,但不包含任何動態數據,內容在構建后也不會被改變,一個鏡像可以創建多個容器 |
| Docker 容器 Container | 容器是獨立運行、相互隔離的一個或一組應用,是鏡像創建的運行實例,實質是進程,可以看作為一個簡易版的 Linux 環境 + 運行在其中的應用程序 |
| Docker 客戶端 Client | 客戶端通過命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 與 Docker 的守護進程通信 |
| Docker 主機 Host | 一個物理或者虛擬的機器用于執行 Docker 守護進程和容器 |
| Docker 倉庫 Repository | 集中存放鏡像文件的地方,分為公有倉庫和私有倉庫。 |
| Docker 注冊服務器 Registry | 是一個集中存儲、分發鏡像的服務,官方的叫 Docker Hub。一個 Docker Registry 中可包含多個倉庫,每個倉庫可以包含多個標簽 Tag 的鏡像,不同的標簽對應不同的版本 |
| Docker Machine | Docker Machine 是一個簡化 Docker 安裝的命令行工具,通過一個簡單的命令行即可在相應的平臺上安裝Docker,比如 VirtualBox、 Digital Ocean、Microsoft Azure |
容器的生命周期圖示
容器的生命周期
容器的五個核心狀態,也就是圖中色塊表示的:Created、Running、Paused、Stopped、Deleted:
- Created:容器已經被創建,容器所需的相關資源已經準備就緒,但容器中的程序還未處于運行狀態。
- Running:容器正在運行,也就是容器中的應用正在運行。
- Paused:容器已暫停,表示容器中的所有程序都處于暫停 ( 不是停止 ) 狀態。
- Stopped:容器處于停止狀態,占用的資源和沙盒環境都依然存在,只是容器中的應用程序均已停止。
- Deleted:容器已刪除,相關占用的資源及存儲在 Docker 中的管理信息也都已釋放和移除。
本文主要關注于使用,就不太贅述這些狀態的切換等,下面直接上手。
5. 基本使用
5.1 操作命令
- # 開啟 Docker 開機自啟動
- $ sudo systemctl enable docke
- # 關閉 Docker 開機自啟動
- $ sudo systemctl disable docke
5.2 鏡像命令
- # 去下載鏡像,先從本地找,沒有去鏡像,最后沒有去 hub,標簽不寫默認為 lastest
- $ docker pull [鏡像名]:[標簽Tag]
- # 列出本機的所有 image 文件,-a 顯示本地所有鏡像(包括中間鏡像),-q 只顯示鏡像ID,--digests 顯示鏡像的摘要信息
- $ docker image ls
- $ docker images
- # 刪除 image 文件, -f 強制刪除鏡像
- $ docker rmi [鏡像名][:標簽Tag]
- $ docker rmi [鏡像名1][:標簽Tag] [鏡像名2][:標簽Tag] # 刪多個
- $ docker rmi $(docker ps -a -q) # 刪全部,后面是子命令
- # 查詢鏡像名稱,--no-trunc 顯示完整的鏡像描述,--filter=stars=30 列出star不少于指定值的鏡像,--filter=is-automated=true 列出自動構建類型的鏡像
- $ docker search [關鍵字]
- # 下載鏡像,標簽 tag 不寫默認為 lastest,也可以自己加比如 :3.2.0
- $ docker pull [鏡像名][:標簽Tag]
5.3 容器命令
- # 列出本機正在運行的容器,-a 列出本機所有容器包括終止運行的容器,-q 靜默模式只顯示容器編號,-l 顯示最近創建的容器
- $ docker container ls # 等價于下面這個命令
- $ docker ps
- # 新建并啟動容器
- $ docker run [option] [容器名]
- # 啟動容器
- $ docker start [容器ID]/[容器Names]
- # 重啟容器
- $ docker restart [容器ID]/[容器Names]
- # 終止容器運行
- $ docker kill [容器ID] # 強行終止,相當于向容器里面的主進程發出 SIGKILL 信號,那些正在進行中的操作會全部丟失
- $ docker kill $(docker ps -a -q) # 強行終止所有容器
- $ docker stop [容器ID] # 從容終止,相當于向容器里面的主進程發出 SIGTERM 信號,然后過一段時間再發出 SIGKILL 信號
- $ docker stop $(docker ps -a -q) # 終止所有容器
- # 終止運行的容器文件,依然會占據硬盤空間,可以使用 docker container rm 命令刪除,-f 強制刪除可以刪除正在運行的容器
- $ docker rm [容器ID]
- $ docker rm `docker ps -aq` # 刪除所有已經停止的容器,因為沒停止的rm刪不了需要加-f
- # 查看容器的輸出,-t加入時間戳,-f跟隨最新日志打印,--tail數字顯示最后多少條,如果docker run時,沒有使用-it,就要用這個命令查看輸出
- $ docker logs [容器ID]
- # 查看容器進程信息
- $ docker top [容器ID]/[容器Names]
- $ docker port [容器ID]/[容器Names]
- # 退出容器
- $ exit # 容器退出
- ctrl + p + q # 容器退出,快捷鍵
- # 進入容器
- $ docker attach [容器ID] # 退出容器時會讓容器停止,本機的輸入直接輸到容器中
- $ docker exec -it [容器ID] # 退出容器時不會讓容器停止,在已運行的容器中執行命令,不創建和啟動新的容器
- # 設置容器在docker啟動時自動啟動
- $ docker container update --restart=always [容器名字]
這里要特別說一下 docker run 的 option,因為最常用:
- --name 為容器指定一個名稱;
- -d 容器啟動后進入后臺,并返回容器 ID,即啟動守護式容器;
- -P 隨機端口映射;
- -p 80:8080 將本地 80 端口映射到容器的 8080 端口;
- bash 容器啟動以后,內部第一個執行的命令。這里啟動 bash,保證用戶可以使用 Shell;
- -i 以交互模式運行容器,通常與 -t 同時使用;
- -t 為容器重新分配一個偽輸入終端,容器的 Shell 會映射到當前的 Shell,然后在本機窗口輸入的命令,就會傳入容器,通常與 -i 同時使用;
- --rm 在容器終止運行后自動刪除容器文件;
- --restart=always 設置容器自啟動;
- -v /xxx:/yyy 映射命令,把本機的 xxx 目錄映射到容器中的 yyy 目錄,也就是說改變本機的 xxx 目錄下的內容, 容器 yyy 目錄中的內容也會改變;
比如我在 CentOS 下跑起來一個 CentOS 的 Docker 容器:
- # 下載
- $ docker pull centos
- # 在上面下載的 centos 鏡像基礎上,新建一個容器名為 mycentos0901 的 centos 實例,并進入這個容器的 bash
- $ docker run -it --name mycentos0901 0d120b6ccaa8
- [root@169c9fffeecd /] # 進入容器,下面輸入命令,注意這里 root 后面的一串 ID
- $ ls # 可以看到centos的根目錄文件列表
- $ docker # bash: docker: command not found 這個容器沒有安裝docke
是不是很神奇,我們可以在一開始的 CentOS 下面執行 docker ps 來查看容器列表:
image-20200901225909737
你會發現上面那個 ID,正是下面列表中跑起來的這個容器的 ID,鏡像的 ID 也是我們前面 pull 下來的 CentOS 鏡像 ID,名字也是我們起的 mycentos0901。
如果 docker run 之后報 Conflict. The container name "xxxx" is already in use by container 就直接運行 docker rm $(docker ps -a -q) 刪除已停止的容器,或者精確刪除 docker rm [containerID] 也可以,就可以了。
5.4 幾個常見場景的命令使用
守護式啟動容器
使用 centos 以后臺模式啟動一個容器 docker run -d --name mycentos0903 0d120b6ccaa8,啟動之后 docker ps -a 查看,發現容器并不在運行中,這是因為 Docker 的運行機制:Docker 容器后臺運行,必須有一個前臺進程。
容器運行的命令如果不是那些一直掛起的命令,比如 top、tail ,運行結束會自動退出。所以為了讓容器持續在后臺運行,那么需要將運行的程序以前臺進程的形式運行。
比如這里在后臺運行一個命令,這個命令一直在打印 docker run -d centos /bin/sh -c "while true; do echo hello zzyy; sleep 2; done",然后我們 logs 查看一下:
docker_logs
退出容器后對容器操作
退出容器后可以通過 exec 方法對正在運行的容器進行操作:
image-20200911142617186
在容器中拷貝文件到外部
拷貝文件使用 cp 命令
- $ docker cp [容器ID]/[容器Names]:[要拷貝的文件目錄] [本機目錄] # 容器文件拷貝到本機
- $ docker cp [本機目錄] [容器ID]/[容器Names]:[要拷貝的文件目錄] # 本機文件拷貝到容器
cp 不僅能把容器中的文件/文件夾拷貝到本機,也可以把本機中的文件/文件夾拷貝到容器。
演示一下,這里先到容器里面創建一個無聊的文件 xixi.txt,然后拷貝到本機:
image-20200921210352644
實用的時候,我們可以拷貝配置、日志等文件到本地。
6. 安裝 MySQL
- # 查詢鏡像
- $ docker search mysql
- # 下載鏡像,實測沒配置鏡像加速的時候會比較慢,配置了就好一些
- $ docker pull mysql
- # 查看鏡像
- $ docker images
- # 創建并運行容器
- $ docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=888888 -v /Users/sherlocked93/Personal/configs/mysql.d:/etc/mysql/conf.d --name localhost-mysql mysql
稍微解釋一下上面的參數:
- -p 3307:3306 將本機的 3307 端口映射到 mysql 容器的 3306 端口,根據需要自行更改;
- -e MYSQL_ROOT_PASSWORD=
設置遠程登錄的 root 用戶密碼; - --name
可選,設置容器別名; - -v xxx/mysql.d:/etc/mysql/conf.d 將本地目錄下設置文件夾映射到容器的 /etc/mysql/conf.d
- -v xxx/logs:/logs 將本機指定目錄下的 logs 目錄掛載到容器的 /logs
- -v xxx/data:/var/lib/mysql 將主機制定目錄下的 data 目錄掛載到容器的 /var/lib/mysql
運行截圖:
安裝Mysql
然后去 Navicat 中就可以連接到 MySQL 了。
這也太爽了!真的是幾行命令就裝好了啊,比之前真是快樂多了 ??
7. 安裝 Nginx
Nginx 的安裝和其他的類似,如果你還不太了解 Nginx 如何使用,可以參看
- # 查詢/下載鏡像
- $ docker search nginx
- $ docker pull nginx
image-20200922203203685
然后創建一個臨時的容器,目的是把默認配置拷貝到本機,我這里把配置文件放到 /mnt 目錄下,主要是三個配置文件夾:
- /etc/nginx 放置 Nginx 配置文件;
- /var/log/nginx/ 放置 Nginx 日志文件;
- /usr/share/nginx/html/ 放置 Nginx 前端靜態文件都放在這個文件夾;
分別把這幾個目錄都拷貝到本機的 /mnt 文件夾下的 nginx、nginx_logs、html 文件夾。
剛剛創建的臨時容器沒用了 docker rm -f [臨時容器ID] 把臨時容器干掉,然后 docker run 重新創建 Nginx 容器:
- $ docker run -d --name localhost-nginx -p 8082:80 \
- -v /mnt/nginx:/etc/nginx \
- -v /mnt/nginx_logs:/var/log/nginx \
- -v /mnt/html:/usr/share/nginx/html \
- --privileged=true nginx
--privileged=true 表示容器內部對掛載的目錄擁有讀寫等特權。
其他配置剛剛上面之前已經講過,應該不用講了。
image-20200922204931582
然后在你自己瀏覽器上就可以訪問了,如果是云服務器,記得開放對應端口。
8. 安裝 Easy Mock
因為 Easy Mock 依賴 Redis 和 MongoDB,因此本地環境使用 docker-compose 來搭建 Easy Mock 應該算是最佳實踐了。
安裝 docker-compose
官方文檔:https://docs.docker.com/compose/install/
首先你得確定擁有 docker 環境,如果你是 Windows / Mac 用戶,那么安裝客戶端,就會自帶 docker-compose 了。
因為本次我們是在云服務器 CentOS7.6 上搭建,所以我們需要自行安裝 docker-compose,運行如下命令,下載當前穩定版本的 docker-compose
- $ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(unam
修改文件權限為可執行文件
- $ sudo chmod +x /usr/local/bin/docker-compose
驗證是否安裝成功
- $ docker-compose version
編寫 docker-compose.yml 配置文件
可以參考官方文檔給出的部署文檔,也可以參考我下面的配置過程。
首先新建文件 docker-compose.yml 并將下面 docker-compose 文件內容復制進入 docker-compose.yml,然后將內容中注釋位置替換為自己需要的本地地址
- version: '3'
- services:
- mongodb:
- image: mongo:3.4.1
- volumes:
- # /apps/easy-mock/data/db 是數據庫文件存放地址,根據需要修改為本地地址
- - '/apps/easy-mock/data/db:/data/db'
- networks:
- - easy-mock
- restart: always
- redis:
- image: redis:4.0.6
- command: redis-server --appendonly yes
- volumes:
- # /apps/easy-mock/data/redis 是 redis 數據文件存放地址,根據需要修改為本地地址
- - '/apps/easy-mock/data/redis:/data'
- networks:
- - easy-mock
- restart: always
- web:
- image: easymock/easymock:1.6.0
- # easy-mock 官方給出的文件,這里是 npm start,這里修改為 npm run dev
- command: /bin/bash -c "npm run dev:server"
- ports:
- - 7300:7300 # 改為你自己期望的映射
- volumes:
- # 日志地址,根據需要修改為本地地址
- - '/apps/easy-mock/logs:/home/easy-mock/easy-mock/logs'
- networks:
- - easy-mock
- restart: always
- networks:
- easy-mock:
啟動 Easy Mock
在 docker-compose 文件目錄下,運行如下命令:
- $ docker-compose up -d
如果遇到 easymock docker 實例報文件權限錯誤
- Error: EACCES: permission denied....
要在項目根目錄執行以下命令
- $ chmod 777 /yourfile/logs
然后就可以通過瀏覽器上的 你的域名.com:7300 訪問到 easy-mock 了!
如果你覺得域名后面跟著端口號挺難看的,你可以通過配置 Nginx 的二級域名來訪問你部署的 easy-mock,配置二級域名的方法參見 這篇文章
9. 可視化管理
關于可視化查詢工具,這里就簡單推介一個 LazyDocker,由于是在終端運行的,而且支持鍵盤操作和鼠標點擊,就挺騷氣的,有了這個一些查詢語句可以少打幾次了。
lzd
安裝比較簡單,運行下面的命令:
- $ docker run --rm -it -v \
- /var/run/docker.sock:/var/run/docker.sock \
- -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker \
- lazyteam/lazydocke
可以設置一個終端的 alias
- $ alias lzd='docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker lazyteam/lazydocker'
然后你在終端輸入 lzd 就可以瀏覽你的鏡像、容器、日志、配置、狀態等等內容了。
10. 結語
由于在下目前使用 Docker 的主要場景是 MySQL、Nginx 之類工具的安裝,所以本文所介紹的內容也大多屬于這個場景。
篇幅原因 Docker 還有一些內容本文沒有介紹,但上面的內容已基本滿足日常的使用,其他 Docker 的內容可以關注一下在下的后續文章~
網上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學習過程中的總結,如果發現錯誤,歡迎留言指出~
參考文檔:
- Empowering App Development for Developers | Docker 官方網站
- Docker核心技術(基礎篇)
- Docker安裝mysql
- Docker文檔
- Docker-compose文檔
- 使用 docker 運行 easy-mock - 知乎
- docker-compose easy-mock - 簡書
- 使用 docker 運行 easy-mock | CodingDiary
- easymock官方docker倉庫:easy-mock/easy-mock-docker
- 使用docker安裝nginx











































