0. 前言
文章已經收錄到 GitHub 個人部落格專案,歡迎 Star:
https://github.com/chenyl8848/chenyl8848.github.io
或者訪問網站,進行線上瀏覽:
https://chenyl8848.github.io/
1. Docker 簡介
1.1 官方定義
官方介紹:
- We have a complete container solution for you - no matter who you are and where you are on your containerization journey.
- 翻譯:我們為你提供了一個完整的容器解決方案,不管你是誰。不管你在哪,你都可以開始容器的的旅程。
官方定義:Docker 是一個容器技術。
- 官網首頁
關注微信公眾號:【Java 陳序員】,獲取開源專案分享、AI 副業分享、超 200 本經典計算機電子書籍等。
1.2 Docker 的起源
Docker 最初是 dotCloud 公司創始人 Solomon Hykes 在法國期間發起的一個公司內部專案,它是基於 dotCloud 公司多年雲服務技術的一次革新,並於 2013 年 3 月以 Apache2.0 授權協議開源,主要專案程式碼在 GitHub 上進行維護。Docker 專案後來還加入了 Linux 基金會,併成立推動開放容器聯盟(OCI).
Docker 自開源後受到廣泛的關注和討論,由於 Docker 專案的火爆,在 2013 年底,dotCloud 公司決定改名為 Docker. Docker 最初是在 Ubuntu 12.04 上開發實現的;Red Hat 則從 RHEL 6.5 開始對 Docker 進行支援;Google 也在其 PaaS 產品中廣泛應用 Docker.
Docker 使用 Google 公司推出的 Go 語言進行開發實現,基於 Linux 核心的 cgroup、namespace, 以及 OverlayFS 類的 Union FS 等技術,對程序進行封裝隔離,屬於作業系統層面的虛擬化技術。由於隔離的程序獨立於宿主和其它的隔離的程序,因此也稱其為容器。
1.3 Docker 的優勢
在開發的時候,在本機測試環境可以跑,生產環境跑不起來。
這裡我們拿 Java Web 應用程式舉例,我們一個 Java Web 應用程式涉及很多東西,比如 JDK、Tomcat、MySQL 等軟體環境。當這些其中某一項版本不一致的時候,可能就會導致應用程式跑不起來這種情況。Docker 則將程式以及使用軟體環境直接打包在一起,無論在那個機器上保證了環境一致。
優勢 1:一致的執行環境,更輕鬆的遷移。
伺服器自己的程式掛了,結果發現是別人程式出了問題把記憶體吃完了,自己程式因為記憶體不夠就掛了。
這種也是一種比較常見的情況,如果你的程式重要性不是特別高的話,公司基本上不可能讓你的程式獨享一臺伺服器的,這時候你的伺服器就會跟公司其他人的程式共享一臺伺服器,所以不可避免地就會受到其他程式的干擾,導致自己的程式出現問題。Docker 就很好解決了環境隔離的問題,別人程式不會影響到自己的程式。
優勢 2:對程序進行封裝隔離,容器與容器之間互不影響,更高效的利用系統資源。
公司要弄一個活動,可能會有大量的流量進來,公司需要再多部署幾十臺伺服器。
在沒有 Docker 的情況下,要在幾天內部署幾十臺伺服器,這對運維來說是一件非常折磨人的事,而且每臺伺服器的環境還不一定一樣,就會出現各種問題,最後部署地頭皮發麻。用 Docker 的話,我只需要將程式打包到映象,你要多少臺服務,我就跑多少容器,極大地提高了部署效率。
優勢 3:透過映象複製 N 多個環境一致容器。
1.4 Docker 和虛擬機器的區別
關於 Docker 與虛擬機器的區別,在網上找到的一張圖,非常直觀形象地展示出來,話不多說,直接上圖。
比較上面兩張圖,我們發現虛擬機器是攜帶作業系統,本身很小的應用程式卻因為攜帶了作業系統而變得非常大,很笨重。Docker 是不攜帶作業系統的,所以 Docker 的應用就非常的輕巧。另外在呼叫宿主機的 CPU、磁碟等等這些資源的時候,拿記憶體舉例,虛擬機器是利用 Hypervisor 去虛擬化記憶體,整個呼叫過程是虛擬記憶體->虛擬實體記憶體->真正實體記憶體,但是 Docker 是利用 Docker Engine 去呼叫宿主的的資源,這時候過程是虛擬記憶體->真正實體記憶體。
傳統虛擬機器 | Docker 容器 | |
---|---|---|
磁碟佔用 | 幾個 GB 到幾十個 GB 左右 | 幾十 MB 到幾百 MB 左右 |
CPU 記憶體佔用 | 虛擬作業系統非常佔用 CPU 和記憶體 | Docker 引擎佔用極低 |
啟動速度 | (從開機到執行專案)幾分鐘 | (從開啟容器到執行專案)幾秒 |
安裝管理 | 需要專門的運維技術 | 安裝、管理方便 |
應用部署 | 每次部署都費時費力 | 從第二次部署開始輕鬆簡捷 |
耦合性 | 多個應用服務安裝到一起,容易互相影響 | 每個應用服務一個容器,達成隔離 |
系統依賴 | 無 | 需求相同或相似的核心,目前推薦是 Linux |
2. Docker 的安裝
2.1 安裝 Docker(centos7.x)
- 解除安裝原始 Docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
- 安裝 Docker 依賴
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
- 設定 Docker 的 yum 源
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
- 安裝最新版的 Docker
sudo yum install docker-ce docker-ce-cli containerd.io
- 指定版本安裝 Docker
yum list docker-ce --showduplicates | sort -r
# sudo yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
sudo yum install docker-ce-18.09.5-3.el7 docker-ce-cli-18.09.5-3.el7 containerd.io
- 啟動 Docker
sudo systemctl enable docker
sudo systemctl start docker
- 關閉 Docker
sudo systemctl stop docker
- 測試 Docker 是否安裝
sudo docker --version
2.2 bash 安裝(通用所有平臺)
在測試或開發環境中 Docker 官方為了簡化安裝流程,提供了一套便捷的安裝指令碼,CentOS 系統上可以使用這套指令碼安裝。另外可以透過 --mirror
選項使用國內源進行安裝。
執行這個命令後,指令碼就會自動的將一切準備工作做好,並且把 Docker 的穩定(stable)版本安裝在系統中。
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
- 啟動 Docker
sudo systemctl enable docker
sudo systemctl start docker
- 建立 Docker 使用者組
sudo groupadd docker
- 將當前使用者加入 Docker 組
sudo usermod -aG docker $USER
- 測試 Docker 是否安裝
docker --version
3. Docker 的核心架構
映象
:一個映象代表一個應用環境,他是一個只讀的檔案,如 MySQL 映象、Tomcat 映象、Nginx 映象等容器
:映象每次執行之後就是產生一個容器,就是正在執行的映象,特點就是可讀可寫倉庫
:用來存放映象的位置,類似於 Maven 倉庫,也是映象下載和上傳的位置dockerFile
Docker 生成映象配置檔案,用來書寫自定義映象的一些配置tar
:一個對映象打包的檔案,日後可以還原成映象
4. Docker 配置阿里映象加速服務
4.1 Docker 執行流程
4.2 Docker 配置阿里雲映象加速
- 訪問阿里雲登入自己賬號檢視 Docker 映象加速服務,並依照如下命令進行修改
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://lz2nib3q.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
- 驗證 Docker 的映象加速是否生效
[root@localhost ~]# docker info
..........
127.0.0.0/8
Registry Mirrors:
'https://lz2nib3q.mirror.aliyuncs.com/'
Live Restore Enabled: false
Product License: Community Engine
5. Docker 的入門應用
docker run hello-world
[root@localhost ~]# docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
6. Docker 常用命令
6.1 輔助命令
# 1.安裝完成輔助命令
docker version -------------------------- 檢視 Docker 的資訊
docker info -------------------------- 檢視更詳細的資訊
docker --help -------------------------- 幫助命令
6.2 Images 映象命令
# 1.檢視本機中所有映象
docker images -------------------------- 列出本地所有映象
-a 列出所有映象(包含中間映像層)
-q 只顯示映象 id
# 2.搜尋映象
docker search [options] 映象名 ------------------- 去 dockerhub 上查詢當前映象
-s 指定值 列出收藏數不少於指定值的映象
--no-trunc 顯示完整的映象資訊
# 3.從倉庫下載映象
docker pull 映象名[:TAG|@DIGEST] ----------------- 下載映象
# 4.刪除映象
docker rmi 映象名 -------------------------- 刪除映象
-f 強制刪除
6.3 Contrainer 容器命令
# 1.執行容器
docker run 映象名 -------------------------- 映象名新建並啟動容器
--name 別名為容器起一個名字
-d 啟動守護式容器(在後臺啟動容器)
-p 對映埠號:原始埠號 指定埠號啟動
例:docker run -it --name myTomcat -p 8888:8080 tomcat
docker run -d --name myTomcat -P tomcat
# 2.檢視執行的容器
docker ps -------------------------- 列出所有正在執行的容器
-a 正在執行的和歷史執行過的容器
-q 靜默模式,只顯示容器編號
# 3.停止|關閉|重啟容器
docker start 容器名字或者容器id --------------- 開啟容器
docker restart 容器名或者容器id --------------- 重啟容器
docker stop 容器名或者容器id ------------------ 正常停止容器執行
docker kill 容器名或者容器id ------------------ 立即停止容器執行
# 4.刪除容器
docker rm -f 容器id和容器名
docker rm -f $(docker ps -aq) -------------------------- 刪除所有容器
# 5.檢視容器內程序
docker top 容器id或者容器名 ------------------ 檢視容器內的程序
# 6.檢視檢視容器內部細節
docker inspect 容器id ------------------ 檢視容器內部細節
# 7.檢視容器的執行日誌
docker logs [OPTIONS] 容器id或容器名 ------------------ 檢視容器日誌
-t 加入時間戳
-f 跟隨最新的日誌列印
--tail 數字 顯示最後多少條
# 8.進入容器內部
docker exec [options] 容器id 容器內命令 ------------------ 進入容器執行命令
-i 以互動模式執行容器,通常與-t一起使用
-t 分配一個偽終端 shell視窗 bash
# 9.容器和宿主機之間複製檔案
docker cp 檔案|目錄 容器id:容器路徑 ----------------- 將宿主機複製到容器內部
docker cp 容器id:容器內資源路徑 宿主機目錄路徑 ----------------- 將容器內資源複製到主機上
# 10.資料卷(volum)實現與宿主機共享目錄
docker run -v 宿主機的路徑|任意別名:/容器內的路徑 映象名
注意: 1. 如果是宿主機路徑必須是絕對路徑,宿主機目錄會覆蓋容器內目錄內容 2. 如果是別名則會在 Docker 執行容器時自動在宿主機中建立一個目錄,並將容器目錄檔案複製到宿主機中
# 11.打包映象
docker save 映象名 -o 名稱.tar
# 12.載入映象
docker load -i 名稱.tar
# 13.容器打包成新的映象
docker commit -m "描述資訊" -a "作者資訊" (容器id或者名稱)打包的映象名稱:標籤
7. Docker 的映象原理
7.1 映象是什麼?
映象是一種輕量級的,可執行的獨立軟體包,用來打包軟體執行環境和基於執行環境開發的軟體,它包含執行某個軟體所需的所有內容,包括程式碼、執行時所需的庫、環境變數和配置檔案。
7.2 為什麼一個映象會那麼大?
映象就像是花捲。
UnionFS(聯合檔案系統):Union 檔案系統是一種分層,輕量級並且高效能的檔案系統,它支援對檔案系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下。
Union 檔案系統是 Docker 映象的基礎。這種檔案系統特性:就是一次同時載入多個檔案系統,但從外面看起來,只能看到一個檔案系統,聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄。
7.3 Docker 映象原理
Docker 的映象實際是由一層一層的檔案系統組成。
- bootfs(boot file system)主要包含 bootloader 和 kernel. bootloader 主要是引導載入 kernel,Linux 剛啟動時會載入 bootfs 檔案系統。在 Docker 映象的最底層就是 bootfs.這一層與 Linux/Unix 系統是一樣的,包含 boot 載入器(bootloader)和核心(kernel).當 boot 載入完後,整個核心就都在記憶體中了,此時記憶體的使用權已由 bootfs 轉交給核心,此時會解除安裝 bootfs.
- rootfs(root file system),在 bootfs 之上,包含的就是典型的 Linux 系統中的 /dev、/proc、/bin、/etc 等標準的目錄和檔案。rootfs 就是各種不同的作業系統發行版,比如 Ubuntu/CentOS 等等。
- 我們平時安裝進虛擬機器的 Centos 都有 1 到幾個 GB,為什麼 Docker 這裡才 200MB?對於一個精簡的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程式庫就可以了,因為底層直接使用 Host 的 Kernal,自己只需要提供 rootfs 就行了。由此可見不同的 Linux 發行版,他們的 bootfs 是一致的,rootfs 會有差別,因此不同的發行版可以共用 bootfs.
7.4 為什麼 Docker 映象要採用這種分層結構呢?
最大的一個好處就是資源共享。
比如:有多個映象都是從相同的 base 映象構建而來的,那麼宿主機只需在磁碟中儲存一份 base 映象。同時記憶體中也只需要載入一份 base 映象,就可以為所有容器服務了,而且映象的每一層都可以被共享。
Docker 映象都是隻讀的。當容器啟動時,一個新的可寫層被載入到映象的頂部。這一層通常被稱為容器層,容器層之下都叫映象層。
8.Docker 安裝常用服務
8.1 安裝 MySQL
# 1.拉取 mysql 映象到本地
docker pull mysql:tag (tag不加預設最新版本)
# 2.執行 mysql 服務
docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:tag --沒有暴露外部埠外部不能連線
docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql:tag --沒有暴露外部埠
# 3.進入 mysql 容器
docker exec -it 容器名稱|容器id bash
# 4.外部檢視 mysql 日誌
docker logs 容器名稱|容器id
# 5.使用自定義配置引數
docker run --name mysql -v /root/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -d mysql:tag
# 6.將容器資料位置與宿主機位置掛載保證資料安全
docker run --name mysql -v /root/mysql/data:/var/lib/mysql -v /root/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql:tag
# 7.透過其他客戶端訪問 如在 window 系統|macos 系統使用客戶端工具訪問
# 8.將 MySQL 資料庫備份為 SQL 檔案
docker exec mysql|容器id sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql --匯出全部資料
docker exec mysql sh -c 'exec mysqldump --databases 庫表 -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql --匯出指定庫資料
docker exec mysql sh -c 'exec mysqldump --no-data --databases 庫表 -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql --匯出指定庫資料不要資料
# 9.執行 SQL 檔案到 MySQL 中
docker exec -i mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /root/xxx.sql
8.2 安裝 Redis
# 1.在 Docker Hub 搜尋 Redis 映象
docker search redis
# 2.拉取 Redis 映象到本地
docker pull redis
# 3.啟動 Redis 服務執行容器
docker run --name redis -d redis:tag (沒有暴露外部埠)
docker run --name redis -p 6379:6379 -d redis:tag (暴露外部宿主機埠為6379進行連線)
# 4.檢視啟動日誌
docker logs -t -f 容器id|容器名稱
# 5.進入容器內部檢視
docker exec -it 容器id|名稱 bash
# 6.載入外部自定義配置啟動 redis 容器
預設情況下 Redis 官方映象中沒有 redis.conf 配置檔案,需要去官網下載指定版本的配置檔案
1. wget http://download.redis.io/releases/redis-5.0.8.tar.gz 下載官方安裝包
2. 將官方安裝包中配置檔案進行復制到宿主機指定目錄中如 /root/redis/redis.conf 檔案
3. 修改需要自定義的配置
bind 0.0.0.0 開啟遠端許可權
appenonly yes 開啟aof持久化
4. 載入配置啟動
docker run --name redis -v /root/redis:/usr/local/etc/redis -p 6379:6379 -d redis redis-server /usr/local/etc/redis/redis.conf
# 7.將資料目錄掛在到本地保證資料安全
docker run --name redis -v /root/redis/data:/data -v /root/redis/redis.conf:/usr/local/etc/redis/redis.conf -p 6379:6379 -d redis redis-server /usr/local/etc/redis/redis.conf
8.3 安裝 Nginx
# 1.在 Docker Hub 搜尋 Nginx
docker search nginx
# 2.拉取 Nginx 映象到本地
[root@localhost ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
afb6ec6fdc1c: Pull complete
b90c53a0b692: Pull complete
11fa52a0fdc0: Pull complete
Digest: sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
# 3.啟動 Nginx 容器
docker run -p 80:80 --name nginx01 -d nginx
# 4.進入容器
docker exec -it nginx01 /bin/bash
查詢目錄: whereis nginx
配置檔案: /etc/nginx/nginx.conf
# 5.複製配置檔案到宿主機
docker cp nginx01(容器id|容器名稱):/etc/nginx/nginx.conf 宿主機名錄
# 6.掛在 nginx 配置以及 html 到宿主機外部
docker run --name nginx02 -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf -v /root/nginx/html:/usr/share/nginx/html -p 80:80 -d nginx
8.4 安裝 Tomcat
# 1.在 Docker Hub 搜尋 Tomcat
docker search tomcat
# 2.下載 Tomcat 映象
docker pull tomcat
# 3.執行 Tomcat 映象
docker run -p 8080:8080 -d --name mytomcat tomcat
# 4.進入 Tomcat 容器
docker exec -it mytomcat /bin/bash
# 5.將 webapps 目錄掛載在外部
docker run -p 8080:8080 -v /root/webapps:/usr/local/tomcat/webapps -d --name mytomcat tomcat
8.5 安裝 MongoDB 資料庫
# 1.執行 MongoDB
docker run -d -p 27017:27017 --name mymongo mongo ---無須許可權
docker logs -f mymongo --檢視mongo執行日誌
# 2.進入 MongoDB 容器
docker exec -it mymongo /bin/bash
直接執行 mongo 命令進行操作
# 3.常見具有許可權的容器
docker run --name mymongo -p 27017:27017 -d mongo --auth
# 4.進入容器配置使用者名稱密碼
mongo
# 選擇 admin 庫
use admin
# 建立使用者,此使用者建立成功,則後續操作都需要使用者認證
db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})
exit
# 5.將 MongoDB 中資料目錄對映到宿主機中
docker run -d -p 27017:27017 -v /root/mongo/data:/data/db --name mymongo mongo
8.6 安裝 ElasticSearch
注意:需要調高 JVM 執行緒數限制數量。
- 拉取映象執行 ElasticSearch
# 1.拉取 ElasticSearch 映象
docker pull elasticsearch:6.4.2
# 2.檢視 Docker 映象
docker images
# 3.執行 ElasticSearch 映象
docker run -p 9200:9200 -p 9300:9300 elasticsearch:6.4.2
若啟動出現如下錯誤,按照如下步驟修改。
- 預先配置
# 1.在 CentOS 虛擬機器中,修改配置 sysctl.conf
vim /etc/sysctl.conf
# 2.加入如下配置
vm.max_map_count=262144
# 3.啟用配置
sysctl -p
注:這一步是為了防止啟動容器時,報出如下錯誤:bootstrap checks failed max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
- 啟動 EleasticSearch 容器
# 0.複製容器中 data 目錄到宿主機中
docker cp 容器id:/usr/share/share/elasticsearch/data /root/es
# 1.執行 EleasticSearch 容器,指定 JVM 記憶體大小並指定 IK 分詞器位置
docker run -d --name es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms128m -Xmx128m" -v /root/es/plugins:/usr/share/elasticsearch/plugins -v /root/es/data:/usr/share/elasticsearch/data elasticsearch:6.4.2
- 安裝 IK 分詞器
# 1.下載對應版本的 IK 分詞器
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.2/elasticsearch-analysis-ik-6.4.2.zip
# 2.解壓到 plugins 資料夾中
yum install -y unzip
unzip -d ik elasticsearch-analysis-ik-6.4.2.zip
# 3.新增自定義擴充套件詞和停用詞
cd plugins/elasticsearch/config
vim IKAnalyzer.cfg.xml
<properties>
<comment>IK Analyzer 擴充套件配置</comment>
<!--使用者可以在這裡配置自己的擴充套件字典 -->
<entry key="ext_dict">ext_dict.dic</entry>
<!--使用者可以在這裡配置自己的擴充套件停止詞字典-->
<entry key="ext_stopwords">ext_stopwords.dic</entry>
</properties>
# 4.在 IK 分詞器目錄下 config 目錄中建立 ext_dict.dic 檔案,編碼一定要為 UTF-8 才能生效
vim ext_dict.dic 加入擴充套件詞即可
# 5. 在 IK 分詞器目錄下 config 目錄中建立 ext_stopword.dic 檔案
vim ext_stopwords.dic 加入停用詞即可
# 6.重啟容器生效
docker restart 容器id
# 7.將此容器提交成為一個新的映象
docker commit -a="xiaochen" -m="es with IKAnalyzer" 容器id xiaochen/elasticsearch:6.4.2
- 安裝 Kibana
# 1.下載 Kibana 映象到本地
docker pull kibana:6.4.2
# 2.啟動 Kibana 容器
docker run -d --name kibana -e ELASTICSEARCH_URL=http://10.15.0.3:9200 -p 5601:5601 kibana:6.4.2
10. Docker 中出現如下錯誤解決方案
[root@localhost ~]# docker search mysql 或者 docker pull 這些命令無法使用
Error response from daemon: Get https://index.docker.io/v1/search?q=mysql&n=25: x509: certificate has expired or is not yet valid
注意:這個錯誤的原因在於是系統的時間和 Docker Hub 時間不一致,需要做系統時間與網路時間同步。
# 1.安裝時間同步
sudo yum -y install ntp ntpdate
# 2.同步時間
sudo ntpdate cn.pool.ntp.org
# 3.檢視本機時間
date
# 4.重新測試
11. Dockerfile
11.1 什麼是 Dockerfile
Dockerfile 可以認為是Docker 映象的描述檔案,是由一系列命令和引數構成的指令碼。主要作用是用來構建 Docker 映象的構建檔案。
透過架構圖可以看出透過 DockerFile 可以直接構建映象。
11.2 Dockerfile 解析過程
11.3 Dockerfile 的保留命令
官方說明:https://docs.docker.com/engine/reference/builder/
保留字 | 作用 |
---|---|
FROM | 當前映象是基於哪個映象的 第一個指令必須是FROM |
MAINTAINER | 映象維護者的姓名和郵箱地址 |
RUN | 構建映象時需要執行的指令 |
EXPOSE | 當前容器對外暴露出的埠號 |
WORKDIR | 指定在建立容器後,終端預設登入進來的工作目錄,一個落腳點 |
ENV | 用來在構建映象過程中設定環境變數 |
ADD | 將宿主機目錄下的檔案複製進映象且 ADD 命令會自動處理 URL 和解壓 tar 包 |
COPY | 類似於 ADD,複製檔案和目錄到映象中<br/>將從構建上下文目錄中原路徑的檔案/目錄複製到新的一層的映象內的目標路徑位置 |
VOLUME | 容器資料卷,用於資料儲存和持久化工作 |
CMD | 指定一個容器啟動時要執行的命令<br/>Dockerfile 中可以有多個 CMD 指令,但只有最後一個生效,CMD 會被 docker run 之後的引數替換 |
ENTRYPOINT | 指定一個容器啟動時要執行的命令<br/>ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程式及其引數 |
11.3.1 FROM 命令
基於哪個映象進行構建新的映象,在構建時會自動從 Docker Hub 拉取 base 映象,必須作為 Dockerfile 的第一個指令出現。
語法:
FROM <image>
FROM <image>[:<tag>] 使用版本不寫為latest
FROM <image>[@<digest>] 使用摘要
11.3.2 MAINTAINER 命令
映象維護者的姓名和郵箱地址[廢棄]。
語法:
MAINTAINER <name>
11.3.3 RUN 命令
RUN 命令將在當前映像之上的新層中執行任何命令並提交結果,生成的提交映像將用於 Dockerfile 中的下一步。
語法:
RUN <command> (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
RUN echo hello
RUN ["executable", "param1", "param2"] (exec form)
RUN ["/bin/bash", "-c", "echo hello"]
11.3.4 EXPOSE 命令
用來指定構建的映象在執行為容器時對外暴露的埠。
語法:
EXPOSE 80/tcp 如果沒有顯示指定則預設暴露都是tcp
EXPOSE 80/udp
11.3.5 CMD 命令
用來為啟動的容器指定執行的命令,在 Dockerfile 中只能有一條 CMD 指令。如果列出多個命令,則只有最後一個命令才會生效。
語法:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
11.3.6 WORKDIR 命令
用來為 Dockerfile 中的任何 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令設定工作目錄。如果 WORKDIR 不存在,即使它沒有在任何後續 Dockerfile 指令中使用,它也將被建立。
語法:
WORKDIR /path/to/workdir
WORKDIR /a
WORKDIR b
WORKDIR c
注意:WORKDIR 指令可以在 Dockerfile 中多次使用。如果提供了相對路徑,則該路徑將與先前 WORKDIR 指令的路徑相對。
11.3.7 ENV 命令
用來為構建映象設定環境變數,這個值將出現在構建階段中所有後續指令的環境中。
語法:
ENV <key> <value>
ENV <key>=<value> ...
11.3.8 ADD 命令
用來從 context 上下文複製新檔案、目錄或遠端檔案 url,並將它們新增到位於指定路徑的映像檔案系統中。
語法:
ADD hom* /mydir/ 萬用字元新增多個檔案
ADD hom?.txt /mydir/ 萬用字元新增
ADD test.txt relativeDir/ 可以指定相對路徑
ADD test.txt /absoluteDir/ 也可以指定絕對路徑
ADD url
11.3.9 COPY 命令
用來將 context 目錄中指定檔案複製到映象的指定目錄中。
語法:
COPY src dest
COPY ["<src>",... "<dest>"]
11.3.10 VOLUME 命令
用來定義容器執行時可以掛在到宿主機的目錄。
語法:
VOLUME ["/data"]
11.3.11 ENTRYPOINT 命令
用來指定容器啟動時執行命令和 CMD 類似。
語法:
["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
- ENTRYPOINT 指令,往往用於設定容器啟動後的第一個命令,這對一個容器來說往往是固定的。
- CMD 指令,往往用於設定容器啟動的第一個命令的預設引數,這對一個容器來說可以是變化的。
11.3.11 ENTRYPOINT 命令
11.4 Dockerfile 構建 SpringBoot 專案部署
- 準備 SpringBoot 可執行專案
- 將可執行專案放入 Linux 虛擬機器中
- 編寫 Dockerfile
FROM openjdk:8
WORKDIR /ems
ADD ems.jar /ems
EXPOSE 8989
ENTRYPOINT ["java","-jar"]
CMD ["ems.jar"]
- 構建映象
[root@localhost ems]# docker build -t ems .
- 執行映象
[root@localhost ems]# docker run -p 8989:8989 ems
- 訪問專案
http://10.15.0.8:8989/ems/login.html
12. 高階網路配置
12.1 說明
當 Docker 啟動時,會自動在主機上建立一個 docker0
虛擬網橋,實際上是 Linux 的一個 bridge,可以理解為一個軟體交換機,它會在掛載到它的網口之間進行轉發。
同時,Docker 隨機分配一個本地未佔用的私有網段(在 RFC1918 中定義)中的一個地址給 docker0
介面。比如典型的 172.17.42.1
,掩碼為 255.255.0.0
。此後啟動的容器內的網口也會自動分配一個同一網段(172.17.0.0/16
)的地址。
當建立一個 Docker 容器的時候,同時會建立了一對 veth pair
介面(當資料包傳送到一個介面時,另外一個介面也可以收到相同的資料包)。這對介面一端在容器內,即 eth0
;另一端在本地並被掛載到 docker0
網橋,名稱以 veth
開頭(例如 vethAQI2QT
)。透過這種方式,主機可以跟容器通訊,容器之間也可以相互通訊。Docker 就建立了在主機和所有容器之間一個虛擬共享網路。
12.2 Docker 網路操作命令
- 檢視網路資訊
docker network ls
- 建立一個網橋
docker network create -d bridge 網橋名稱
- 刪除一個網橋
docker network rm 網橋名稱
12.3 容器之間使用網路通訊
# 1.查詢當前網路配置
docker network ls
NETWORK ID NAME DRIVER SCOPE
8e424e5936b7 bridge bridge local
17d974db02da docker_gwbridge bridge local
d6c326e433f7 host host local
# 2.建立橋接網路
docker network create -d bridge info
[root@centos ~]# docker network create -d bridge info
6e4aaebff79b1df43a064e0e8fdab08f52d64ce34db78dd5184ce7aaaf550a2f
[root@centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
8e424e5936b7 bridge bridge local
17d974db02da docker_gwbridge bridge local
d6c326e433f7 host host local
6e4aaebff79b info bridge local
# 3.啟動容器指定使用網橋
docker run -d -p 8890:80 --name nginx001 --network info nginx
docker run -d -p 8891:80 --name nginx002 --network info nginx
注意:一旦指定網橋後--name 指定名字就是主機名,多個容器指定在同一個網橋時,可以在任意一個容器中使用主機名與容器進行互通。
[root@centos ~]# docker run -d -p 8890:80 --name nginx001 --network info nginx
c315bcc94e9ddaa36eb6c6f16ca51592b1ac8bf1ecfe9d8f01d892f3f10825fe
[root@centos ~]# docker run -d -p 8891:80 --name nginx002 --network info nginx
f8682db35dd7fb4395f90edb38df7cad71bbfaba71b6a4c6e2a3a525cb73c2a5
[root@centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8682db35dd7 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:8891->80/tcp nginx002
c315bcc94e9d nginx "/docker-entrypoint.…" 7 minutes ago Up 7 minutes 0.0.0.0:8890->80/tcp nginx001
b63169d43792 mysql:5.7.19 "docker-entrypoint.s…" 7 minutes ago Up 7 minutes 3306/tcp mysql_mysql.1.s75qe5kkpwwttyf0wrjvd2cda
[root@centos ~]# docker exec -it f8682db35dd7 /bin/bash
root@f8682db35dd7:/# curl http://nginx001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.....
13. 高階資料卷配置
13.1 說明
資料卷是一個可供一個或多個容器使用的特殊目錄,它繞過 UFS,可以提供很多有用的特性:
資料卷
可以在容器之間共享和重用- 對
資料卷
的修改會立馬生效 - 對
資料卷
的更新,不會影響映象 資料卷
預設會一直存在,即使容器被刪除
注意:資料卷
的使用,類似於 Linux 下對目錄或檔案進行 mount,映象中的被指定為掛載點的目錄中的檔案會複製到資料卷中(僅資料卷為空時會複製)。
13.2 資料卷操作命令
- 建立資料卷
[root@centos ~]# docker volume create my-vol
my-vol
- 檢視資料卷
[root@centos ~]# docker volume inspect my-vol
[
{
"CreatedAt": "2020-11-25T11:43:56+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
- 掛載資料卷
[root@centos ~]# docker run -d -P --name web -v my-vol:/usr/share/nginx/html nginx
[root@centos ~]# docker inspect web
"Mounts": [
{
"Type": "volume",
"Name": "my-vol",
"Source": "/var/lib/docker/volumes/my-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
- 刪除資料卷
docker volume rm my-vol
14. Docker Compose
14.1 簡介
Docker Compose
專案是 Docker 官方的開源專案,負責實現對 Docker 容器叢集的快速編排。從功能上看,跟 OpenStack
中的 Heat
十分類似。
其程式碼目前在 https://github.com/docker/compose 上開源。
Docker Compose
定位是定義和執行多個 Docker 容器的應用(Defining and running multi-container Docker applications),其前身是開源專案 Fig.
透過前面的介紹,我們知道使用一個 Dockerfile
模板檔案,可以讓使用者很方便的定義一個單獨的應用容器。然而,在日常工作中,經常會碰到需要多個容器相互配合來完成某項任務的情況。例如要實現一個 Web 專案,除了 Web 服務容器本身,往往還需要再加上後端的資料庫服務容器,甚至還包括負載均衡容器等。
Docker Compose
恰好滿足了這樣的需求。它允許使用者透過一個單獨的 docker-compose.yml
模板檔案(YAML 格式)來定義一組相關聯的應用容器為一個專案(project)。
Docker Compose
中有兩個重要的概念:
- 服務 (
service
):一個應用的容器,實際上可以包括若干執行相同映象的容器例項。 - 專案 (
project
):由一組關聯的應用容器組成的一個完整業務單元,在docker-compose.yml
檔案中定義。
Docker Compose
的預設管理物件是專案,透過子命令對專案中的一組容器進行便捷地生命週期管理。
Docker Compose
專案由 Python 編寫,實現上呼叫了 Docker 服務提供的 API 來對容器進行管理。因此,只要所操作的平臺支援 Docker API,就可以在其上利用 Docker Compose
來進行編排管理。
14.2 安裝與解除安裝
- 安裝
- Linux
在 Linux 上的也安裝十分簡單,從官方 GitHub Release 處直接下載編譯好的二進位制檔案即可。例如,在 Linux64 位系統上直接下載對應的二進位制包。
curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
- MacOS、Window
Docker Compose 可以透過 Python 的包管理工具 pip 進行安裝,也可以直接下載編譯好的二進位制檔案使用,甚至能夠直接在 Docker 容器中執行。
Docker Desktop for Mac/Windows 自帶 docker-compose 二進位制檔案,安裝 Docker 之後可以直接使用
。
- bash 命令補全
curl -L https://raw.githubusercontent.com/docker/compose/1.25.5/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
- 解除安裝
如果是二進位制包方式安裝的,刪除二進位制檔案即可。
rm /usr/local/bin/docker-compose
- 測試安裝成功
docker-compose --version
14.3 Docker Compose 使用
- 相關概念
首先介紹幾個術語。
- 服務 (
service
):一個應用容器,實際上可以執行多個相同映象的例項。 - 專案 (
project
):由一組關聯的應用容器組成的一個完整業務單元。一個專案可以由多個服務(容器)關聯而成,Docker Compose
面向專案進行管理。
- 場景
最常見的專案是 Web 網站,該專案應該包含 Web 應用和快取。
- SpringBoot 應用
- MySQL 服務
- Redis 服務
- ElasticSearch 服務
- .......
- docker-compose 模板
參考文件:https://docker_practice.gitee.io/zh-cn/compose/compose_file.html
version: "3.0"
services:
mysqldb:
image: mysql:5.7.19
container_name: mysql
ports:
- "3306:3306"
volumes:
- /root/mysql/conf:/etc/mysql/conf.d
- /root/mysql/logs:/logs
- /root/mysql/data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
networks:
- ems
depends_on:
- redis
redis:
image: redis:4.0.14
container_name: redis
ports:
- "6379:6379"
networks:
- ems
volumes:
- /root/redis/data:/data
command: redis-server
networks:
ems:
- 透過 docker-compose 執行一組容器
參考文件:https://docker_practice.gitee.io/zh-cn/compose/commands.html
# 前臺啟動一組服務
docker-compose up
# 後臺啟動一組服務
docker-compose up -d
14.4 docker-compose 模板檔案
模板檔案是使用 Docker Compose
的核心,涉及到的指令關鍵字也比較多。但大家不用擔心,這裡面大部分指令跟 docker run
相關引數的含義都是類似的。
預設的模板檔名稱為 docker-compose.yml
,格式為 YAML 格式。
version: "3"
services:
webapp:
image: examples/web
ports:
- "80:80"
volumes:
- "/data"
注意每個服務都必須透過 image
指令指定映象或 build
指令(需要 Dockerfile)等來自動構建生成映象。
如果使用 build
指令,在 Dockerfile
中設定的選項(例如:CMD
, EXPOSE
, VOLUME
, ENV
等) 將會自動被獲取,無需在 docker-compose.yml
中重複設定。
下面分別介紹各個指令的用法。
build
指定 Dockerfile
所在資料夾的路徑(可以是絕對路徑,或者相對 docker-compose.yml 檔案的路徑)。Docker Compose
將會利用它自動構建這個映象,然後使用這個映象。
version: '3'
services:
webapp:
build: ./dir
也可以使用 context
指令指定 Dockerfile
所在資料夾的路徑。
使用 dockerfile
指令指定 Dockerfile
檔名。
使用 arg
指令指定構建映象時的變數。
version: '3'
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
command
覆蓋容器啟動後預設執行的命令。
command: echo "hello world"
container_name
指定容器名稱。預設將會使用 專案名稱_服務名稱_序號
這樣的格式。
container_name: docker-web-container
注意: 指定容器名稱後,該服務將無法進行擴充套件(scale),因為 Docker 不允許多個容器具有相同的名稱。
depends_on
解決容器的依賴、啟動先後的問題。以下例子中會先啟動 redis
、db
再啟動 web
.
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
注意:web
服務不會等待redis
db
「完全啟動」之後才啟動。
env_file
從檔案中獲取環境變數,可以為單獨的檔案路徑或列表。
如果透過 docker-compose -f FILE
方式來指定 Docker Compose 模板檔案,則 env_file
中變數的路徑會基於模板檔案路徑。
如果有變數名稱與 environment
指令衝突,則按照慣例,以後者為準。
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
環境變數檔案中每一行必須符合格式,支援 #
開頭的註釋行。
# common.env: Set development environment
PROG_ENV=development
environment
設定環境變數。你可以使用陣列或字典兩種格式。
只給定名稱的變數會自動獲取執行 Docker Compose 主機上對應變數的值,可以用來防止洩露不必要的資料。
environment:
RACK_ENV: development
SESSION_SECRET:
environment:
- RACK_ENV=development
- SESSION_SECRET
如果變數名稱或者值中用到 true|false,yes|no
等表達 布林 含義的詞彙,最好放到引號裡,避免 YAML 自動解析某些內容為對應的布林語義。這些特定詞彙,包括
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
healthcheck
透過命令檢查容器是否健康執行。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
image
指定為映象名稱或映象 ID。如果映象在本地不存在,Docker Compose
將會嘗試拉取這個映象。
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
networks
配置容器連線的網路。
version: "3"
services:
some-service:
networks:
- some-network
- other-network
networks:
some-network:
other-network:
ports
暴露埠資訊。
使用宿主埠:容器埠 (HOST:CONTAINER)
格式,或者僅僅指定容器的埠(宿主將會隨機選擇埠)都可以。
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
注意:當使用 HOST:CONTAINER
格式來對映埠時,如果你使用的容器埠小於 60 並且沒放到引號裡,可能會得到錯誤結果,因為 YAML
會自動解析 xx:yy
這種數字格式為 60 進位制。為避免出現這種問題,建議數字串都採用引號包括起來的字串格式。
sysctls
配置容器核心引數。
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
ulimits
指定容器的 ulimits 限制值。
例如,指定最大程序數為 65535,指定檔案控制代碼數為 20000(軟限制,應用可以隨時修改,不能超過硬限制) 和 40000(系統硬限制,只能 root 使用者提高)。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
volumes
資料卷所掛載路徑設定。可以設定為宿主機路徑(HOST:CONTAINER
)或者資料卷名稱(VOLUME:CONTAINER
),並且可以設定訪問模式 (HOST:CONTAINER:ro
)。
該指令中路徑支援相對路徑。
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
如果路徑為資料卷名稱,必須在檔案中配置資料卷。
version: "3"
services:
my_src:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
14.5 docker-compose 常用命令
- 命令物件與格式
對於 Docker Compose 來說,大部分命令的物件既可以是專案本身,也可以指定為專案中的服務或者容器。如果沒有特別的說明,命令物件將是專案,這意味著專案中所有的服務都會受到命令影響。
執行 docker-compose [COMMAND] --help
或者 docker-compose help [COMMAND]
可以檢視具體某個命令的使用格式。
docker-compose
命令的基本的使用格式是
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
- 命令選項
-f, --file FILE
指定使用的 Compose 模板檔案,預設為docker-compose.yml
,可以多次指定。-p, --project-name NAME
指定專案名稱,預設將使用所在目錄名稱作為專案名。--x-networking
使用 Docker 的可拔插網路後端特性--x-network-driver DRIVER
指定網路後端的驅動,預設為bridge
--verbose
輸出更多除錯資訊。-v, --version
列印版本並退出。
- 命令使用說明
up
格式為:docker-compose up [options] [SERVICE...]
.
- 該命令十分強大,它將嘗試自動完成包括構建映象,(重新)建立服務,啟動服務,並關聯服務相關容器的一系列操作。
- 連結的服務都將會被自動啟動,除非已經處於執行狀態。
- 可以說,大部分時候都可以直接透過該命令來啟動一個專案。
- 預設情況,
docker-compose up
啟動的容器都在前臺,控制檯將會同時列印所有容器的輸出資訊,可以很方便進行除錯。- 當透過
Ctrl-C
停止命令時,所有容器將會停止。- 如果使用
docker-compose up -d
,將會在後臺啟動並執行所有的容器。一般推薦生產環境下使用該選項。- 預設情況,如果服務容器已經存在,
docker-compose up
將會嘗試停止容器,然後重新建立(保持使用volumes-from
掛載的卷),以保證新啟動的服務匹配docker-compose.yml
檔案的最新內容
down
此命令將會停止 up
命令所啟動的容器,並移除網路。
exec
進入指定的容器。
ps
列出專案中目前的所有容器。
格式為:docker-compose ps [options] [SERVICE...]
.
選項:-q
只列印容器的 ID 資訊。
restart
重啟專案中的服務。
格式為:docker-compose restart [options] [SERVICE...]
.
選項:-t, --timeout TIMEOUT
指定重啟前停止容器的超時(預設為 10 秒)。
rm
刪除所有(停止狀態的)服務容器。推薦先執行 docker-compose stop
命令來停止容器。
格式為:docker-compose rm [options] [SERVICE...]
.
選項:
-f, --force
強制直接刪除,包括非停止狀態的容器。一般儘量不要使用該選項。-v
刪除容器所掛載的資料卷。start
啟動已經存在的服務容器。
格式為:docker-compose start [SERVICE...]
。
stop
停止已經處於執行狀態的容器,但不刪除它。透過 docker-compose start
可以再次啟動這些容器。
格式為:docker-compose stop [options] [SERVICE...]
.
選項:-t, --timeout TIMEOUT
停止容器時候的超時(預設為 10 秒)。
top
檢視各個服務容器內執行的程序。
unpause
恢復處於暫停狀態中的服務。
格式為 docker-compose unpause [SERVICE...]
.
15. Docker 視覺化工具
15.1 安裝 Portainer
官方安裝說明:http://www.yunweipai.com/go?_=8fe4813824aHR0cHM6Ly93d3cucG9ydGFpbmVyLmlvL2luc3RhbGxhdGlvbi8=
[root@ubuntu1804 ~]#docker pull portainer/portainer
[root@ubuntu1804 ~]#docker volume create portainer_data
portainer_data
[root@ubuntu1804 ~]#docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
20db26b67b791648c2ef6aee444a5226a9c897ebcf0160050e722dbf4a4906e3
[root@ubuntu1804 ~]#docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20db26b67b79 portainer/portainer "/portainer" 5 seconds ago Up 4 seconds 0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp portainer
15.2 登入和使用 Portainer
用瀏覽器訪問:http://localhost:9000