Docker版本選擇:
Docker之前沒有區分版本,但是2017年推出(將docker更名為)新的專案Moby,github地址:https://github.com/moby/moby,Moby專案屬于Docker專案的全新上游,Docker將是一個隸屬于的Moby的子產品,而且之后的版本之后開始區別為CE版本(社區版本)和EE(企業收費版),CE社區版本和EE企業版本都是每個季度發布一個新版本,但是EE版本提供后期安全維護1年,而CE版本是4個月
Docker安裝
下載rpm包安裝:
官方rpm包下載地址:
https : //download.docker.com/linux/centos/7/x86_64/stable/Packages/阿里全世界下載地址:
https ://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/
Centos yum源安裝:
- 下載docker源
rm -rf /etc/yum.repos.d/* wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 安裝
yum install docker-ce
- 啟動
systemctl start docker
systemctl enable docker
Ubuntu安裝
版本:Ubuntu 18.04.3
參考:https ://yq.aliyun.com/articles/110806
- 阿里腳本安裝最新版
- 使用官方安裝腳本自動安裝(僅適用于公網環境)
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
- 自定義版本下載
- 配置阿里yum源
sudo vim /etc/apt/sources.list deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
- 安裝必要的一些系統工具
sudo apt-get update sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
2. 安裝GPG證書
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
3. 寫入軟體源資訊
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
4. 更新
sudo apt-get -y update
5. 發現Docker-CE的版本:
# apt-cache madison docker-ce docker-ce | 5:19.03.2~3-0~ubuntu-bionic | http://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic/stable amd64 Packages docker-ce | 5:19.03.1~3-0~ubuntu-bionic | http://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic/stable amd64 Packages
6. 安裝指定版本的Docker-CE:(VERSION例如上面的17.03.1?ce-0?ubuntu-xenial)
sudo apt install docker-ce-cli=5:18.09.9~3-0~ubuntu-bionic sudo apt install docker-ce=5:18.09.9~3-0~ubuntu-bionic
7. 驗證版本

- 驗證docker資訊 (以下是ubuntu安裝的資訊)
# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 18.09.9
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc version: 425e105d5a03fabd737a126ad93d62a9eeede87f
init version: fec3683
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.15.0-62-generic
Operating System: Ubuntu 18.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.861GiB
Name: ubuntu
ID: 2C5Z:IASC:G3GK:325R:RDGI:GDJ4:23EE:O76B:Z2RY:HY5U:RSLC:J7OO
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine
WARNING: No swap limit support
最后一行有個警告:警告:不支持交換限制
解決方法:
sudo vim /etc/default/grub 在GRUB_CMDLINE_LINUX=""這行加上 GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
更新下grub,然后重啟
sudo update-grub reboot
Docker命令
- 查看資訊
docker info
- 查看版本
docker version
- 查看當前容器狀態
docker ps
4. 搜索nginx的鏡像(第一個是默認的,也是下載最多的)
docker search nginx

5. 下載nginx的鏡像
docker pull nginx

6. 查看已經下載的鏡像串列,TAG版本號默認都是latest
docker images

7、進入容器后,安裝基礎命令:
apt update
apt install procps
apt install iputils-ping
apt install net-tools
啟動容器
# 啟動一個在后臺運行的 docker 容器
docker run -it -d --name 'test-nginx' nginx
# -p指定埠映射,
-p 80:80
# 指定 ip 地址和傳輸協議 udp 或者 tcp:
-p 192.168.7.108:80:80/tcp
# 也可以在創建時手動指定容器的 dns
--dns 223.6.6.6
# 指定名稱
--name "centos3"

vi docker-enter.sh chmod +x docker-enter.sh
進入容器
- 使用執行命令方式進入容器
docker exec -it b7a13ace208d bash

- 使用使用容器pid方式進入容器
docker inspect -f "{{.State.Pid}}" 02a1907e7c89 19080 nsenter -t 19080 -m -u -i -n -p

3. 腳本方式進入容器
#!/bin/bash docker_in(){ NAME_ID=$1 PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID}) nsenter -t ${PID} -m -u -i -n -p } docker_in $1
啟動
./docker-enter.sh centos-test
更多命令
以名義名:nginx為例子
- 洗掉docker的nginx鏡像檔案
docker rmi nginx

2. 手動匯出docker鏡像
docker save nginx -o /root/nginx.tar.gz docker save nginx > /root/nginx.tar.gz
- 手動匯入docker僅限
docker save nginx -o /root/nginx.tar.gz docker save nginx > /root/nginx.tar.gz
- 停止和啟動一個容器
# d5ab2595f09a是CONTAINER ID
docker stop d5ab2595f09a
docker start d5ab2595f09a
- 洗掉一個已經停止的容器
docker rm d5ab2595f09a
- 強制關閉一個運行中的容器
docker kill d1ad4fa0b74c
docker加快加速配置:
國內下載國外的某些有時候會很慢,因此可以更改docker組態檔添加一個加速器,可以通過加速器達到加速下載替代的目的,
獲取加速地址:
瀏覽器打開http://cr.console.aliyun.com,編碼或登錄阿里云賬號,單擊垂直的嵌套加速器,將會得到一個專屬的加速地址,而且下面有使用配置說明:

1. 可以通過修改daemon組態檔/etc/docker/daemon.json來使用加速器
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["你的加速地址"] } EOF
2. 重啟服務
sudo systemctl daemon-reload sudo systemctl restart docker
使用docker info 查看

Docker命令與鏡像管理:
Docker 鏡像含有啟動容器所需要的檔案系統及所需要的內容, 因此鏡像主要用于創建并啟動 docker 容器,
Docker 鏡像含里面是一層層檔案系統,叫做 Union FS(聯合檔案系統) ,聯合檔案系統,可以將幾層目錄掛載到一起,形成一個虛擬檔案系統,虛擬檔案系統的目錄結構就像普通 linux 的目錄結構一樣, docker 通過這些檔案再加上宿主機的內核提供了一個 linux 的虛擬環境,每一層檔案系統我們叫做一層 layer,聯合檔案系統可以對每一層檔案系統設定三種權限,只讀( readonly)、讀寫( readwrite)和寫出( whiteout-able),但是 docker 鏡像中每一層檔案系統都是只讀的,構建鏡像的時候,從一個最基本的作業系統開始,每個構建的操作都相當于做一層的修改,增加了一層檔案系統,一層層往上疊加,上層的修改會覆寫底層該位置的可見性,這也很容易理解,就像上層把底層遮住了一樣,當使用鏡像的時候,我們只會看到一個完全的整體,不知道里面有幾層也不需要知道里面有幾層,結構如下:

一個典型的 Linux 檔案系統由 bootfs 和 rootfs 兩部分組成, bootfs(boot filesystem) 主要包含 bootloader 和 kernel, bootloader 主要用于引導加載 kernel,
當 kernel 被加載到記憶體中后 bootfs 會被 umount 掉, rootfs (root file system) 包含的就是典型 Linux 系統中的/dev, /proc, /bin, /etc 等標準目錄和檔案, 下圖就是 docker image 中最基礎的兩層結構,不同的 linux 發行版(如 ubuntu和 CentOS ) 在 rootfs 這一層會有所區別,但是對于 docker 鏡像通常都比較小, 官方提供的 centos 基礎鏡像在 200MB 左右,一些其他版本的鏡像甚至只有幾 MB, docker 鏡像直接呼叫宿主機的內核,鏡像中只提供 rootfs,也就是只需要包括最基本的命令、工具和程式庫就可以了, 比如 alpine 鏡像,在 5M 左右,
下圖就是有兩個不同的鏡像在一個宿主機內核上實作不同的 rootfs,

容器、 鏡像父鏡像:

docker常用命令示例
- 搜索官方鏡像
# 帶指定版本號 docker search centos:7.2.1511 # 不帶版本號默認 latest docker search centos
- 下載鏡像
docker pull 倉庫服務器:埠/專案名稱/鏡像名稱:版本號
- 查看本地鏡像
docker images
REPOSITORY #鏡像所屬的倉庫名稱
TAG #鏡像版本號(識別符號), 默認為 latest
IMAGE ID #鏡像唯一 ID 標示
CREATED #鏡像創建時間
VIRTUAL SIZE #鏡像的大小
- 鏡像匯出:可以將鏡像從本地匯出問為一個壓縮檔案,然后復制到其他服務器進行匯入使用
# 方法1 docker save centos -o /opt/centos.tar.gz # 方法2 docker save centos > /opt/centos-1.tar.gz
- 查看鏡像內容:包含了鏡像的相關配置, 組態檔、分層
tar xvf centos.tar.gz cat manifest.json
- 鏡像匯入:將鏡像匯入到 docker
docker load < /opt/centos.tar.gz
洗掉鏡像
docker rmi centos
- 洗掉容器(-f 強制)
docker rm 容器 ID/容器名稱
docker命令:
- 命令格式
docker [OPTIONS] COMMAND
- 常用的
COMMAND
[COMMAND]
attach 此方式進入容器的操作都是同步顯示的且 exit 后容器將被關閉
build 從Dockerfile構建一個鏡像
commit 從容器的更改中創建一個新鏡像
cp 在容器和本地檔案系統之間復制檔案/檔案夾
create 創建新容器
diff 檢查容器檔案系統上檔案或目錄的更改
events 從服務器獲取實時事件
exec 在運行的容器中運行命令
export 將容器的檔案系統匯出為tar包
history 顯示鏡像的歷史
images 列出鏡像
import 從tarball匯入內容以創建檔案系統鏡像
info 顯示整個系統的資訊
inspect 回傳Docker物件的底層資訊
kill 停止一個或多個正在運行的容器
load 從tar包或標準輸出加載鏡像
login Log in to a Docker registry
logout Log out from a Docker registry
logs 獲取容器的日志
pause 暫停一個或多個容器中的所有行程
port 列出容器的埠映射或特定映射
ps 列出正在運行的容器
pull 下載鏡像
push 上傳鏡像
rename 重命令一個容器
restart 重啟容器
rm 移除一個或多個容器
rmi 移除一個或多個鏡像
run 在新容器中運行命令
save 將一個或多個影像保存到tar存檔檔案(默認情況下流到STDOUT)
search 在Docker倉庫中搜索鏡像
start 啟動一個或多個處在停止狀態的容器
stats 顯示容器資源使用統計資料的實時流
stop 停止一個或多個正在運行的容器
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top 顯示容器的運行行程
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version 查看版本
wait 阻塞直到一個或多個容器停止,然后列印它們的退出代碼
子命令幫助
docker COMMAND --help
退出容器不注銷:Ctrl + P + Q
run
在新容器中運行命令
- 命令格式
docker run [選項] 鏡像名 [shell 命令] [引數...]
- 常用選項
-p list 指定容器的埠發布到主機
-P 將所有公開的埠發布到隨機埠
--name string 為容器分配一個名稱
-d 在后臺運行容器并列印容器ID
-it 創建并進入容器
--rm 當容器退出時自動洗掉它
例如:
- 啟動的容器在執行完 shell 命令就退出了
#docker run [鏡像名] [shell 命令] docker run centos /bin/echo 'hello wold'
- 從鏡像啟動一個容器:會直接進入到容器, 并隨機生成容器 ID 和名稱
docker run -it docker.io/centos bash
- 隨機映射埠:
前臺啟動并隨機映射本地埠到容器的 80
docker run -P docker.io/nginx
前臺啟動的會話視窗無法進行其他操作,除非退出, 但是退出后容器也會退出隨機埠映射, 其實是默認從 32768 開始
- 指定埠映射:
方式 1:本地埠 81 映射到容器 80 埠:
docker run -p 81:80 --name "nginx-test" nginx
方式 2:本地 IP:本地埠:容器埠
docker run -p 192.168.10.205:82:80 --name "nginx-test" docker.io/nginx
方式 3:本地 IP:本地隨機埠:容器埠
docker run -p 192.168.10.205::80 --name "nginx-test" docker.io/nginx
方式 4:本機 ip:本地埠:容器埠/協議,默認為 tcp 協議
docker run -p 192.168.10.205:83:80/udp --name "nginx-test" docker.io/nginx
方式 5:一次性映射多個埠+協議:
docker run -p 86:80/tcp -p 443:443/tcp -p 53:53/udp --name "nginx-test" docker.io/nginx
5. 后臺啟動容器
docker run -d -P --name "nginx-test" docker.io/nginx
- 容器退出后自動洗掉
docker run -it --rm --name nginx-test docker.io/nginx
- 指定容器 DNS:
Dns 服務,默認采用宿主機的 dns 地址
一是將 dns 地址配置在宿主機
二是將引數配置在 docker 啟動腳本里面 –dns=1.1.1.1
docker run -it --rm --dns 223.6.6.6 centos bash
--rm 容器退出后會洗掉容器
ps
列出正在運行的容器
- 命令格式
docker ps [OPTIONS]
- 常用選項
-a 顯示所有容器(默認顯示正在運行)
-f 根據提供的條件過濾輸出
-n int 顯示最后創建的n個容器(包括所有狀態)(默認值-1)
-l 顯示最新創建的容器(包括所有狀態)
--no-trunc 不截斷輸出
-q 只顯示數字id
-s 顯示總檔案大小
例:
- 顯示正在運行的容器:
docker ps
- 顯示所有容器
docker ps -a
rm
移除一個或多個容器
- 命令格式
docker rm [OPTIONS] CONTAINER [CONTAINER...]
- 常用選項
-f 強制移除正在運行的容器(使用SIGKILL) -l 洗掉指定鏈接 -v 洗掉與容器關聯的卷
例:
- 洗掉運行中的容器:即使容正在運行當中, 也會被強制洗掉掉
docker rm -f 11445b3a84d3 # 11445b3a84d3是CONTAINER ID,通過docker ps 查詢
- 批量洗掉已退出容器
docker rm -f `docker ps -aq -f status=exited`
- 批量洗掉所有容器
docker rm -f $(docker ps -a -q)
logs
獲取容器的日志
- 命令格式
docker logs [OPTIONS] CONTAINER
- 常用選項
--details 顯示提供給日志的額外細節
-f 跟蹤日志輸出
--since string 顯示從時間戳開始的日志(如:42m表示42 分鐘)
--tail string 從日志末尾顯示的行數(默認為“all”)
-t 顯示時間戳
--until string 在時間戳前顯示日志(如:42m表示42 分鐘)
例:
- 查看 Nginx 容器訪問日志
docker logs nginx-test-port3 #一次查看
docker logs -f nginx-test-port3 #持續查看
load
從tar存檔或STDIN加載鏡像
- 命令格式
docker load [OPTIONS]
- 常用選項
-i string 從tar存檔檔案中讀取,而不是從STDIN中讀取
-q 不輸出
例:
- 匯入鏡像
docker load -i nginx.tar.gz
port
列出容器的埠映射或特定映射
- 命令格式
docker port CONTAINER [PRIVATE_PORT[/PROTO]]
- 例:
- 查看容器已經映射的埠
docker port nginx-test
stop
停止一個或多個正在運行的容器
- 命令格式
docker stop [OPTIONS] CONTAINER [CONTAINER...]
- 常用選項
-t int 等待stop幾秒鐘后再殺死它(默認為10)
例:
- 容器的關閉
docker stop f821d0cd5a99
- 批量關閉正在運行的容器
docker stop $(docker ps -a -q)
kill
殺死一個或多個正在運行的容器
- 命令格式
docker kill [OPTIONS] CONTAINER [CONTAINER...]
- 常用選項
-s string 發送到容器的信號(默認為“KILL”)
例:
- 批量強制關閉正在運行的容器
docker kill $(docker ps -a -q)
start
啟動一個或多個停止的容器
- 命令格式
docker start [OPTIONS] CONTAINER [CONTAINER...]
- 常用選項
-a 附加STDOUT/STDERR和轉發信號
--detach-keys string 覆寫用于分離容器的鍵序列
-i 將容器的STDIN
例:
- 容器的啟動
docker start f821d0cd5a99
attach
此方式進入容器的操作都是同步顯示的且 exit 后容器將被關閉
- 命令格式
docker attach [OPTIONS] CONTAINER
- 常用選項
--detach-keys string 覆寫用于分離容器的鍵序列
--no-stdin 不附加STDIN
--sig-proxy 代理所有接收到的行程信號(默認為true)
例:
docker attach 63fbc2d5a3ec
exec
執行單次命令與進入容器,不是很推薦此方式, 雖然 exit 退出容器還在運行
- 命令格式
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
- 常用選項
-d 分離模式:在后臺運行命令
--detach-keys string 覆寫用于分離容器的鍵序列
-e list 設定環境變數
-i 保持STDIN打開,即使沒有連接
--privileged 為該命令授予擴展特權
-t 分配一個pseudo-TTY
-u string 用戶名或UID(格式:< name| UID >[:<group|gid>])
-w string 容器內的作業目錄
例:
- 進入容器
docker exec -it centos-test /bin/bash
inspect
回傳Docker物件的底層資訊
- 命令格式
docker inspect [OPTIONS] NAME|ID ...
- 常用選項
-f string 使用給定的Go模板格式化輸出
例:
- 可以獲取到容器的 PID
# docker inspect -f "{{.State.Pid}}" centos-test3 5892
commit
從容器的更改中創建一個新鏡像
- 命令格式
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
- 常用選項
-a string 作者
-c list 對創建的映像應用Dockerfile指令
-m string 提交訊息
-p 提交期間暫停容器(默認為true)
例:
- 在宿主機基于容器 ID 提交為鏡像
docker commit -a "chen" -m "nginx_yum_v1" --change="EXPOSE_80_443" f5f8c13d0f9f centos-nginx:v1
- 提交的時候標記 tag 號:
> 標記 tag 號,生產當中比較常用,后期可以根據 tag 標記創建不同版本的鏡像以及創建不同版本的容器,
docker commit -m "nginx image" f5f8c13d0f9f jack/centos-nginx:v1
Docker 鏡像與制作
Docker 鏡像有沒有內核?
從鏡像大小上面來說,一個比較小的鏡像只有十幾 MB,而內核檔案需要一百多兆, 因此鏡像里面是沒有內核的, 鏡像在被啟動為容器后將直接使用宿主機的內核, 而鏡像本身則只提供相應的 rootfs, 即系統正常運行所必須的用戶空間的檔案系統,比如/dev/, /proc, /bin, /etc 等目錄, 所以容器當中基本是沒有/boot目錄的,而/boot 當中保存的就是與內核相關的檔案和目錄,
為什么沒有內核?
由于容器啟動和運行程序中是直接使用了宿主機的內核,所以沒有直接呼叫過物理硬體, 所以也不會涉及到硬體驅動, 因此也用不上內核和驅動,另外有內核的那是虛擬機,
手動制作nginx鏡像
Docker 制作類似于虛擬機的鏡像制作,即按照公司的實際業務務求將需要安裝的軟體、相關配置等基礎環境配置完成,然后將其做成鏡像,最后再批量從鏡像批量生產實體,這樣可以極大的簡化相同環境的部署作業, Docker 的鏡像制作分為手動制作和自動制作(基于 DockerFile), 企業通常都是基于 Dockerfile 制作精細, 其中手動制作鏡像步驟具體如下:
下載鏡像并初始化系統:
基于某個基礎鏡像之上重新制作, 因此需要先有一個基礎鏡像,本次使用官方提供的 centos 鏡像為基礎:
1. docker下載centos鏡像,并運行進入
docker pull centos
docker run -it docker.io/centos /bin/bash
- 進入容器
- 進入容器后,更改yun源
yum install wget -y
cd /etc/yum.repos.d/
rm -rf ./*
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
- yum安裝nginx與常用工具
yum install –y nginx wget pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
- 修改nginx配置,關閉后臺運行
vim /etc/nginx/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; daemon off;
4. 自定義 web 頁面
echo "Docker Yum Nginx" > /usr/share/nginx/html/index.html
- 退出容器
5. 提交為鏡像:在宿主機基于容器 ID 提交為鏡像
docker commit -a "xu" -m "nginx_yum_v1" --change="EXPOSE 80 4433" 75f52cfb13d2 centos-nginx:v1

帶 tag 的鏡像提交:
提交的時候標記 tag 號:
標記 tag 號,生產當中比較常用,后期可以根據 tag 標記創建不同版本的鏡像以及創建不同版本的容器,
docker commit -m "nginx image" 75f52cfb13d2 centos-nginx:v3
6. 查看創建的鏡像
docker image ls

7. 從自己鏡像啟動容器,因為本機用的是云主機,沒有備案和域名,所以使用4433埠映射
docker run -d -p 4433:80 --name my-centos-nginx 87e99ab0c9ab /usr/sbin/nginx # 87e99ab0c9ab 是IMAGE ID
8. 訪問測驗

容器埠映射成功
Dockerfile介紹
DockerFile 可以說是一種可以被 Docker 程式解釋的腳本, DockerFile 是由一條條的命令組成的,每條命令對應 linux 下面的一條命令, Docker 程式將這些DockerFile 指令再翻譯成真正的 linux 命令,其有自己的書寫方式和支持的命令, Docker 程式讀取 DockerFile 并根據指令生成 Docker 鏡像,相比手動制作鏡像的方式, DockerFile 更能直觀的展示鏡像是怎么產生的,有了 DockerFile,當后期有額外的需求時,只要在之前的 DockerFile 添加或者修改回應的命令即可重新生成新的 Docke 鏡像,避免了重復手動制作鏡像的麻煩,
FROM 指定基礎鏡像
定制鏡像,需要先有一個基礎鏡像,在這個基礎鏡像上進行定制,FROM 就是指定基礎鏡像,必需放在有效指令的第一行
怎么選擇合適的鏡像呢?官方有nginx、redis、mysql、httpd、tomcat等服務類的鏡像,也有作業系統類,如:centos、ubuntu、debian等,
例:
FROM centos:latest
MAINTAINER 指定維護者資訊
格式
MAINTAINER <name>
RUN 執行命令
RUN 指令是用來執行命令的,shell命令功能豐富,所以RUN 指令經常用來呼叫shell指令,
格式
RUN <command> # 或 RUN ["executable", "param1", "param2"]
第一種不用多說,第二種方式:
RUN ["/bin/bash", "-c", "echo hello world"]
Dockerfile中,每一個指令都會創建一層鏡像,RUN寫多了,創建的鏡像層數就會增多,所以一般RUN 指令的寫法為
RUN yum -y install epel-release \ && yum -y install nginx \ && rm -rf /usr/share/nginx/html/* \ && echo "<h1> docker test nginx </h1>" > /usr/share/nginx/html/index.html
CMD 啟動容器時執行的命令
指定啟動容器時執行的命令,每個 Dockerfile 只能有一條 CMD 命令,如果指定了多條命令,只有最后一潭訓被執行,
支持三種格式
# 使用 exec 執行,推薦方式; CMD ["executable","param1","param2"] # 在 /bin/sh 中執行,提供給需要互動的應用; CMD command param1 param2 # 提供給 ENTRYPOINT 的默認引數; CMD ["param1","param2"]
如果用戶啟動容器時候指定了運行的命令,則會覆寫掉 CMD 指定的命令,
EXPOSE 分配埠號
告訴 Docker 服務端容器暴露的埠號,供互聯系統使用,在啟動容器時需要通過 -P,Docker 主機會自動分配一個埠轉發到指定的埠
格式
EXPOSE <port> [<port>...]
ENV 環境變數
指定一個環境變數,會被后續 RUN 指令使用,并在容器運行時保持,
格式
ENV <key> <value>
例如
ENV PG_MAJOR 9.3 ENV PG_VERSION 9.3.4 RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && … ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
ADD 復制/解壓
該命令將復制指定的
<src>到容器中的<dest>, 其中<src>可以是Dockerfile所在目錄的一個相對路徑;也可以是一個 URL;還可以是一個 tar 檔案(自動解壓為目錄)
格式
ADD <src> <dest>
COPY 復制
復制本地主機的
<src>(為 Dockerfile 所在目錄的相對路徑)到容器中的<dest>
格式
COPY <src> <dest>
當使用本地目錄為源目錄時,推薦使用 COPY
ENTRYPOINT 容器啟動后執行的命令
配置容器啟動后執行的命令,并且不可被 docker run 提供的引數覆寫,
兩種格式:
ENTRYPOINT ["executable", "param1", "param2"]
# shell中執行
ENTRYPOINT command param1 param2
每個 Dockerfile 中只能有一個 ENTRYPOINT,當指定多個時,只有最后一個起效
VOLUME 掛載點
創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放資料庫和需要保持的資料等
格式
VOLUME ["/data"],
USER 指定用戶名
指定運行容器時的用戶名或 UID,后續的 RUN 也會使用指定用戶
格式
USER daemon
當服務不需要管理員權限時,可以通過該命令指定運行用戶,并且可以在之前創建所需要的用戶,
例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres
要臨時獲取管理員權限可以使用 gosu,而不推薦 sudo,
WORKDIR 作業目錄
為后續的 RUN、CMD、ENTRYPOINT 指令配置作業目錄
格式
WORKDIR /path/to/workdir,
可以使用多個 WORKDIR 指令,后續命令如果引數是相對路徑,則會基于之前命令指定的路徑,例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為 /a/b/c,
ONBUILD
配置當所創建的鏡像作為其它新創建鏡像的基礎鏡像時,所執行的操作指令,
格式
ONBUILD [INSTRUCTION]
例如,Dockerfile 使用如下的內容創建了鏡像 image-A,
...
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
...
如果基于 image-A 創建新的鏡像時,新的Dockerfile中使用 FROM image-A指定基礎鏡像時,會自動執行ONBUILD 指令內容,等價于在后面添加了兩條指令,
FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用 ONBUILD 指令的鏡像,推薦在標簽中注明,例如 ruby:1.9-onbuild
構建鏡像
格式
docker build [選項] 路徑
-t選項,指定鏡像的標簽資訊
docker build -t nginx:v1 /usr/local/src/
構建時,目錄內除了構建所需要的檔案,不要有其它檔案
DockerFile 制作yum版 nginx 鏡像:
- 準備目錄
mkdir -pv /opt/dockerfile/web/nginx
- 撰寫dockerfile檔案
vim /opt/dockerfile/web/nginx/Dockerfile
#Nginx web image
FROM centos:latest
RUN yum install epel-release -y
RUN yum install nginx -y && rm -rf /usr/share/nginx/html/*
ADD html.tar.gz /usr/share/nginx/html/
#copy
EXPOSE 80 443 8080
CMD ["/usr/sbin/nginx","-g","daemon off;"]
RUN就是運行shell命令
ADD
- 創建網頁測驗檔案
vi /opt/dockerfile/web/nginx/index.html
<h1> docker nginx test, nginx container by dockerfile</h1>
- 打包網頁測驗檔案
tar czvf html.tar.gz index.html
- 構建鏡像,也可以把此命令寫到腳本里方便以后運行
docker build -t chenjb/centos-nginx /opt/dockerfile/web/nginx/

構建
6. 查看鏡像
docker images

- 啟動容器
docker run -it -d -p 80:80 --name "nginx-test" chenjb/centos-nginx
- 查看行程
docker ps

- 測驗網頁,本機用的是云主機還得配置安全組有點麻煩,這里就直接使用命令列進行測驗了
# curl 127.0.0.1:8355
<h1> docker nginx test, nginx container by dockerfile</h1>

DockerFile 制作編譯版 nginx 鏡像:
下載鏡像并初始化系統:
docker pull centos mkdir -pv /opt/dockerfile/web/nginx
目錄結構按照業務型別或系統型別等方式劃分,方便后期鏡像比較多的時候進行分類
撰寫 Dockerfile:
vim /opt/dockerfile/web/nginx/Dockerfile
生成的鏡像的時候會在執行命令的當前目錄查找 Dockerfile 檔案, 所以名稱不可寫錯, 而且 D 必須大寫
My Dockerfile
"#"為注釋,等于 shell 腳本的中#
除了注釋行之外的第一行,必須是 From xxx (xxx 是基礎鏡像)
# 第一行先定義基礎鏡像,后面的本地有效的鏡像名,如果本地沒有會從遠程倉庫下載,第一行很重要
From centos:latest
# 鏡像維護者的資訊:
MAINTAINER han 583343636@qq.com
#自動解壓壓縮包
ADD nginx-1.16.1.tar.gz /usr/local/src/
#執行的命令,將編譯安裝 nginx 的步驟執行一遍
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/usr/local/nginx --with-http_sub_module && make && make install
RUN cd /usr/local/nginx/
ADD nginx.conf /usr/local/nginx/conf/nginx.conf
RUN useradd nginx -s /sbin/nologin
RUN ln -sv /usr/local/nginx/sbin/nginx /usr/sbin/nginx
RUN echo "Nginx-make version 1.16.1 test page" > /usr/local/nginx/html/index.html
# 向外開放的埠,多個埠用空格做間隔,啟動容器時候-p 需要使用此端向外映射,如: -p 8081:80,則 80 就是這里的 80
EXPOSE 80 443
# 運行的命令,每個 Dockerfile 只能有一條,如果有多條則只有最后一條被執行
CMD ["nginx","-g","daemon off;"]
#如果在從該鏡像啟動容器的時候也指定了命令,那么指定的命令會覆寫Dockerfile 構建的鏡像里面的 CMD 命令,即指定的命令優先級更高, Dockerfile 的優先級較低一些
準備原始碼包與組態檔:
- 配置nginx檔案,并關閉后臺運行添加配置 daemon off
cp /usr/local/nginx/conf/nginx.conf /opt/dockerfile/web/nginx
- nginx 原始碼包
cp /usr/local/src/nginx-1.16.1.tar.gz /opt/dockerfile/web/nginx
- 執行鏡像構建
docker build –t jack/nginx-1.16.1:v1 /opt/dockerfile/web/nginx/
4. 開始構建:可以清晰看到各個步驟執行的具體操作

構建成功了

5. 查看是否生成本地鏡像,如果構建時出錯可能會導致生成名字為none的鏡像,使用命令洗掉即可
docker images
docker rmi -f $(docker images | grep "none" | awk '{print $3}') #過濾出倉庫名和tag名為none的鏡像ID并強制洗掉

6. 從鏡像啟動容器
docker run -d -p 80:80 --name mak1e-nginx peterhx/nginx-make-1.16.1:v1 /usr/sbin/nginx
- 訪問 web 界面

制作 tomcat 鏡像:
基于官方提供的 centos 7.6. 基礎鏡像構建 JDK 和 tomcat 鏡像,先構建 JDK 鏡像,然后再基于 JDK 鏡像構建 tomcat 鏡像,
1、先構建 JDK 鏡像
- 下載基礎鏡像 Centos:
docker pull centos
- 執行構建 JDK 鏡像:
mkdir -pv /opt/dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}}
cd /opt/dockerfile/web/jdk/
- 編輯Dockerfile
# JDK Base Images
FROM centos:latest
ADD jdk-8u212-linux-x64.tar.gz /usr/local/src/
RUN ln -sv /usr/local/src/jdk1.8.0_212 /usr/local/jdk
ADD profile /etc/profile
ENV JAVA_HOME /usr/local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin
RUN rm -rf /etc/localtime \
&& ln -snf /usr/share/zoneinfo/Asia/Shanghai/etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
- 上傳 JDK 壓縮包和 profile 檔案:
將 JDK 壓縮包上傳到 Dockerfile 當前目錄,然后執行構建:
profile檔案內容,(最下邊宣告的環境變數,其他的一樣)
# cat profile
###########################
# System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge export JAVA_HOME=/usr/local/jdk export TOMCAT_HOME=/apps/tomcat export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$TOMCAT_HOME/bin:$PATH export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
執行構建
cat build-command.sh
#!/bin/bash
docker build -t centos-jdk1.8:v1 .

5. 啟動容器
docker run -it centos-jdk1.8:v1 bash
進入容器后,要能查看到Java的環境(如果查不出來等于白做,檢查是哪個環節出錯)

2、從 JDK 鏡像構建 tomcat-8 鏡像
- 進入tomcat目錄:
cd /opt/dockerfile/web/tomcat
- 編輯Dockerfile檔案
vim Dockerfile
FROM centos-jdk:v1
RUN useradd www -u 2020
ENV TZ "Asia/Shanghai"
ENV LANG en_US.UTF-8
ENV TERM xterm
ENV TOMCAT_MAJOR_VERSION 8
ENV TOMCAT_MINOR_VERSION 8.0.49
ENV CATALINA_HOME /apps/tomcat
ENV APP_DIR ${CATALINA_HOME}/webapps
RUN mkdir /apps
ADD apache-tomcat-8.5.42.tar.gz /apps
RUN ln -sv /apps/apache-tomcat-8.5.42 /apps/tomcat
-
上傳 tomcat 壓縮包:
apache-tomcat-8.5.42.tar.gz -
通過腳本構建 tomcat 基礎鏡像
# cat build-command.sh #!/bin/bash docker build -t tomcat85:v1 .

- 驗證鏡像構建完成
docker images

- 構建業務鏡像 app1:
mkdir -p /opt/dockerfile/app/tomcat-app1
cd /opt/dockerfile/app/tomcat-app1/
- 準備 Dockerfile:
vim Dockerfile
FROM tomcat85:v1
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
ADD myapp/* /apps/tomcat/webapps/myapp/
RUN chown www.www /apps/ -R
RUN chmod +x /apps/tomcat/bin/run_tomcat.sh
EXPOSE 8080 8009
CMD ["/apps/tomcat/bin/run_tomcat.sh"]
- 準備自定義 myapp 頁面:
mkdir myapp echo "Docker Tomcat Web Page1" > myapp/index.html
- 準備容器啟動執行腳本:
vim run_tomcat.sh
#!/bin/bash
echo "10.10.10.10 tom.test.com" >> /etc/hosts
echo "nameserver 223.5.5.5" > /etc/resolv.conf
su - www -c "/apps/tomcat/bin/catalina.sh start"
su - www -c "tail -f /etc/hosts"
- 運行命令或執行腳本構建Tomcat-app1鏡像
cat build-command.sh #!/bin/bash docker build -t tomcat85-app1:v1 .

- 查看鏡像
docker images

- 從鏡像啟動容器測驗:
docker run -d -p 8888:8080 tomcat85-app1:v1
訪問測驗

制作 haproxy 鏡像:
- 進入目錄
mkdir -pv /opt/dockerfile/app/haproxy cd /opt/dockerfile/app/haproxy
- 準備 Dockerfile:
vim Dockerfile #Haproxy Base Image FROM centos ADD haproxy-2.0.5.tar.gz /usr/local/src/ RUN yum install gcc gcc-c++ glibc glibc-devel pcre \ pcre-devel openssl openssl-devel systemd-devel \ net-tools vim iotop bc zip unzip zlib-devel lrzsz \ tree screen lsof tcpdump wget ntpdate –y \ && cd /usr/local/src/haproxy-2.0.5 \ && make ARCH=x86_64 TARGET=linux-glibc \ USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 \ USE_SYSTEMD=1 USE_CPU_AFFINITY=1 \ PREFIX=/usr/local/haproxy \ && make install PREFIX=/usr/local/haproxy \ && cp haproxy /usr/sbin/ \ && mkdir /usr/local/haproxy/run ADD haproxy.cfg /etc/haproxy/ ADD run_haproxy.sh /usr/bin RUN chmod +x /usr/bin/run_haproxy.sh EXPOSE 80 9999 CMD ["/usr/bin/run_haproxy.sh"]
-
準備 haproxy 原始碼檔案:
haproxy-2.0.5.tar.gz -
準備
run_haproxy.sh腳本
vim run_haproxy.sh
#!/bin/bash
haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
- 準備 haproxy 組態檔:
vim haproxy.cfg
global
chroot /usr/local/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
nbproc 1
pidfile /usr/local/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:q1w2e3r4ys
listen web_port
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server web1 192.168.99.21:8888 check inter 3000 fall 2 rise 5
server web2 192.168.99.22:8889 check inter 3000 fall 2 rise 5
6. 準備構建腳本:
docker build -t haproxy:v1 .
7. 從鏡像啟動容器:
docker run -it -d -p 80:80 -p 9999:9999 haproxy:v1
8. web 訪問驗證

9. 訪問tomcat業務app1

本地鏡像上傳至官方 docker 倉庫:
將自制的鏡像上傳至 docker 倉庫; https://hub.docker.com/
- 準備賬戶:
登錄到 docker hub 創建官網創建賬戶, 登錄后點擊 settings 完善賬戶資訊,填寫賬戶基本資訊 -
在虛擬機使用自己的賬號登錄
docker login docker.io

- 查看認證資訊:
#登錄成功之后會在當前目錄生成一個隱藏檔案用于保存登錄認證資訊
[root@Server1 ~]# cat /root/.docker/config.json { "auths": { "https://index.docker.io/v1/": { "auth": "cGV0ZXJoeDo5NjExMjFoeC4=" }, "registry.cn-beijing.aliyuncs.com": { "auth": "NTgzMzQzNjM2QHFxLmNvbTo5NjExMjFoeA==" } }, "HttpHeaders": { "User-Agent": "Docker-Client/19.03.8 (linux)" } }
- 查看鏡像 ID
docker images
- 根據規定的格式給鏡像修改tag版本號 并上傳到docker倉庫中

docker tag a187dde48cd2 peterhx/alpine-test:alpine123
docker push peterhx/alpine-test:alpine123
-
上傳完成

7. 到 docker 官網驗證

8. 更換到其他 docker 服務器下載鏡像
# 登錄 docker login docker.io # 下載 docker pull peterhx/alpine-test:alpine123 # 查看 docker images
- 從鏡像啟動一個容器
docker run -it peterhx/alpine-test:alpine123 bash
docker 倉庫之分布式 Harbor
Harbor 是一個用于存盤和分發 Docker 鏡像的企業級 Registry 服務器,由vmware 開源,其通過添加一些企業必需的功能特性,例如安全、標識和管理等,擴展了開源 Docker Distribution,作為一個企業級私有 Registry 服務器,Harbor 提供了更好的性能和安全,提升用戶使用 Registry 構建和運行環境傳輸鏡像的效率, Harbor 支持安裝在多個 Registry 節點的鏡像資源復制,鏡像全部保存在私有 Registry 中, 確保資料和知識產權在公司內部網路中管控, 另外,Harbor 也提供了高級的安全特性,諸如用戶管理,訪問控制和活動審計等,
官網地址: https://vmware.github.io/harbor/cn/,
官方 github 地址:https://github.com/vmware/harbor
Harbor 功能官方介紹:
基于角色的訪問控制:用戶與 Docker 鏡像倉庫通過“專案”進行組織管理,一個用戶可以對多個鏡像倉庫在同一命名空間(project)里有不同的權限,鏡像復制:鏡像可以在多個 Registry 實體中復制(同步),尤其適合于負載均衡,高可用,混合云和多云的場景,圖形化用戶界面:用戶可以通過瀏覽器來瀏覽,檢索當前 Docker 鏡像倉庫,管理專案和命名空間,
AD/LDAP: Harbor 可以集成企業內部已有的 AD/LDAP,用于鑒權認證管理,
審計管理:所有針對鏡像倉庫的操作都可以被記錄追溯,用于審計管理,國際化:已擁有英文、中文、德文、日文和俄文的本地化版本,更多的語言將會添加進來,RESTful API - RESTful API :提供給管理員對于 Harbor 更多的操控, 使得與其它管理軟體集成變得更容易,
部署簡單:提供在線和離線兩種安裝工具, 也可以安裝到 vSphere 平臺(OVA 方式)虛擬設備,
安裝 Harbor:
下載地址:
https://github.com/goharbor/harbor/releases安裝檔案:
https://github.com/vmware/harbor/blob/master/docs/installation_guide.md
本次使用 harbor 版本 1.2.2 離線安裝包,具體名稱為 harbor-offline-installer-v1.7.5.tgz
下載 Harbor 安裝包:
方式1:下載離線安裝包:https://github.com/goharbor/harbor/releases
cd /usr/local/src/ wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.5.tgz
方式2:下載在線安裝包
cd /usr/local/src/ wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-online-installer-v1.7.5.tgz
配置安裝 Harbor:
在另一臺云主機的機器(內網IP為:192.168.0.59)上安裝harbor倉庫
- 解壓
tar xf harbor-offline-installer-v1.7.5.tgz
ln -sv /usr/local/src/harbor /usr/local/
- 下載docker-compose
cd /usr/local/harbor/
yum install python-pip epel-release -y
pip install docker-compose
安裝docker-compose時報錯,缺少依賴及python的開發環境,yum install -y gcc python-devel 即可

- 修改harbor的組態檔,最終配置如下,只修改前兩個即可,其余的根據需要修改
# vim harbor.cfg
...
hostname = 192.168.0.59
...
harbor_admin_password = harbor123
...
其它配置說明
# 寫本機ip,不要寫localho
st或127.0.0.1
hostname = 192.168.0.59
# 訪問UI和令牌/通知服務的協議
ui_url_protocol = http
# harbor DB的根用戶的密碼
db_password = root123
# 最大行程數
max_job_workers = 3
# 確定是否為注冊表的令牌生成證書
customize_crt = on
# 證書路徑
ssl_cert = /data/cert/server.crt
ssl_cert_key = /data/cert/server.key
# 密鑰存盤的路徑
secretkey_path = /data
# Admiral的url,注釋此屬性,或在Harbor獨立時將其值設定為NA
admiral_url = NA
# Clair的postgres資料庫的密碼
clair_db_password = root123
# 電子郵件服務器
email_identity = harbor
email_server = smtp.qq.com
email_server_port = 25
email_username = [email protected]
email_password = 123
email_from = admin <[email protected]>
email_ssl = false
email_insecure = false
# 啟動后從UI更改管理密碼,
harbor_admin_password = root123
# 如果希望根據LDAP服務器驗證用戶的憑證,請將其設定為ldap_auth,
auth_mode = db_auth
ldap_url = ldaps://ldap.mydomain.com
ldap_basedn = ou=people,dc=mydomain,dc=com
ldap_uid = uid
ldap_scope = 3
ldap_timeout = 5
# 打開或關閉自注冊功能
self_registration = on
# 令牌服務創建的令牌的過期時間
token_expiration = 30
# 設定為“adminonly”,以便只有管理員用戶才能創建專案
# 默認值“everyone”允許每個人創建一個專案
project_creation_restriction = everyone
#
verify_remote_cert = on
4. 準備
./prepare
docker-compose.yml 檔案,用于配置資料目錄等配置資訊

5. 運行當前目錄下的腳本開始安裝
./install.sh

安裝完成,可以通過設定的連接通過瀏覽器進行訪問(默認使用的是80,加密埠是443,此主機沒有備案所以下面還需要修改一下埠)

后期修改配置:
如果 harbor 運行一段時間之后需要更改配置,則步驟如下:這里順便修改一下harbor倉庫的訪問的默認埠
1. 先停止 harbor:
cd /usr/local/harbor
docker-compose stop
2. 編輯 harbor.cfg 進行相關配置:(修改之前一定要記得先copy一份)
vim harbor.cfg # 主組態檔不需要修改
# 修改docker-compose.yml檔案,默認訪問的埠映射為888埠
① 這里修改了兩個埠 80改為888,443改為了4433

② 修改完之后還要修改一個檔案
# pwd
/usr/local/harbor/common/templates/registry
[root@Server2 registry]# ls
config.yml config.yml.bak root.crt
[root@Server2 registry]# vim config.yml
url后加上修改后的默認埠,保存退出

③ 修改docker的啟動檔案
#vim /usr/lib/systemd/system/docker.service 修改如下一行 ExecStart=/usr/bin/dockerd --insecure-registry=x.x.x.x:888

修改后重新加載并重啟服務
systemctl daemon-reload && systemctl restart docker.service
3. prepare
./prepare
4. 啟動 harbor 服務:
docker-compose start
登錄測驗一下,登錄成功

常見的2個報錯資訊解答:
(1)Error response from daemon: Get https://192.168.0.59/v1/users/: dial tcp 192.168.0.59:443: getsockopt: connection refused
(2)Error response from daemon: Get https://192.168.0.59:888/v1/users/: http: server gave HTTP response to HTTPS client
報這2個錯誤的都是如下2個原因:
1、是埠錯了!
2、未在docker啟動檔案中添加--insecure-registry信任關系!
大多數這個錯誤是第2個原因,因為你沒有添加信任關系的話,docker默認使用的是https協議,所以埠不對(443),會報連接拒絕這個錯誤;
或者提示你 "服務器給HTTPS端的是HTTP回應" 這個錯誤,因為你沒添加埠信任,服務器認為這是默認的https訪問,回傳的卻是http資料!
解決方法:
正確的添加信任關系包括埠號:
--insecure-registry=192.168.0.59:888
一定要把主機與埠同時添加進去!
繼續
- 查看本地的鏡像

2. 查看本地埠

3. web 瀏覽器訪問 Harbor 管理界面

如果可以正常登錄就說明之前的配置沒毛病,下面就可上傳鏡像了

配置 docker 使用 harbor 倉庫上傳下載鏡像:
- 編輯 docker 組態檔:
注意:如果我們配置的是 https 的話,本地 docker 就不需要有任何操作就可以訪問 harbor 了,在第一臺主機的docker啟動檔案中也添加上內網harbor倉庫的地址
vim /lib/systemd/system/docker.service
在ExecStart追加
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.59:888
- 重啟 docker 服務:
systemctl daemon-reload && systemctl restart docker
- 驗證能否登錄 harbor:
docker login 192.168.0.59:888

如果這里突然遇到密碼錯誤(確認不是忘記了密碼),可以試試重啟docker-compose
docker-compose stop
docker-compose start
- 從server1匯入一個小鏡像,
docker load < /root/alpine.tar.gz
- 驗證鏡像匯入成功(至少要有個鏡像,沒有的話按照上面匯入)
docker images
- 鏡像打 tag:
> 修改 images 的名稱,不修改成指定格式無法將鏡像上傳到 harbor 倉庫,格式為: HarborIP/專案名/image 名字:版本號:
首先要新建一個專案,進入專案里,右側推送鏡像,按照指定格式進行修改才能上傳到此專案中來

- 查看鏡像
docker images

- 修改鏡像的tag號因為使用的埠不一樣,如果是443埠就不需要帶埠號,不過目前也還沒有配置加密證書所以還得帶著埠號才可以
docker tag alpine:latest X.X.X.X:888/alpine/alpine-test2:v4
-
將鏡像 push 到 harbor:因為默認上傳時使用加密的傳輸方式也就是https,這里因為修改了埠所以有些區別
格式為: docker push 鏡像名:版本
docker push x.x.x.x:888/alpine/alpine-test2:v4
- push 完成

-
harbor 界面驗證鏡像上傳成功

-
驗證鏡像資訊

從 harbor 下載鏡像并啟動容器:
- 更改 docker 組態檔:
目前凡是需要從 harbor 鏡像服務器下載 image 的 docker 服務都要更改,不更改的話無法下載:
sudo vim /lib/systemd/system/docker.service
在ExecStart追加 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.59:888
- 重啟 docker:
systemctl daemon-reload
systemctl restart docker
3. 查看下載命令:
-
執行下載:
docker pull X.X.X.X:888/alpine/alpine-test2:v4
- 驗證鏡像下載完成

- 啟動容器:
docker run -it x.x.x.x:888/alpine/alpine-test2:v4 sh
7. 成功啟動,并可以正常使用

實作 harbor 高可用:
Harbor 支持基于策略的 Docker 鏡像復制功能, 這類似于 MySQL 的主從同步, 其可以實作不同的資料中心、 不同的運行環境之間同步鏡像, 并提供友好的管理界面,大大簡化了實際運維中的鏡像管理作業,已經有用很多互聯網公司使用harbor 搭建內網 docker 倉庫的案例,并且還有實作了雙向復制的案列,本文將實作單向復制的部署:
1. 新部署一臺 harbor2 服務器192.168.0.36
程序見前一節
- 驗證從 harbor 登錄,harbor2
- 主 harbor :192.168.0.59
復制的原理是從源harbor上推到目標harbor,所以下面的配置是要在之前創建的harbor上配置,
主harbor:192.168.0.59
從harbor:192.168.0.36
- 主 harbor:創建目標

-
主 harbor:測驗連接成功后,確定

-
從 harbor2:創建一個 alpine 專案:
與主 harbor1 專案名稱保持一致:

-
主 harbor:配置復制

-
主 harbor:點擊復制,新建規則:

-
主 harbor:編輯同步策略

-
主 harbor:查看鏡像同步狀態

-
從 harbor:查看鏡像是否同步成功

測驗從 harbor 鏡像下載和容器啟動:
- 編輯 docker 組態檔:
vim /lib/systemd/system/docker.service
在ExecStart追加
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.36:888 --insecure-registry 192.168.0.59:888
其中 192.168.0.36/59 是我們部署 Harbor 的地址,即 hostname 配置項值,配置完后需要重啟 docker 服務,
- 重啟 docker 服務:
systemctl daemon-reload
systemctl restart docker
- 從 harbor 專案設定為公開:
-
docker 客戶端下載鏡像
docker pull 192.168.0.36:888/alpine/alpine111:v10
5. 下載完后查看鏡像
- docker 客戶端從鏡像啟動容器:
docker run -it 192.168.0.36:888/alpine/alpine111:v10 sh
如果可以從新harbor2上拉取鏡像并運行,就說明harbor已經高可用且同步成功

至此,高可用模式的 harbor 倉庫部署完畢
Docker 資料管理
如果運行中的容器修如果生成了新的資料或者修改了現有的一個已經存在的檔案內容,那么新產生的資料將會被復制到讀寫層進行持久化保存,這個讀寫層也就是容器的作業目錄,此即“寫時復制(COW) copy on write”機制

資料型別:
Docker 的鏡像是分層設計的,底層是只讀的,通過鏡像啟動的容器添加了一層可讀寫的檔案系統,用戶寫入的資料都保存在這一層當中,如果要將寫入的資料永久生效,需要將其提交為一個鏡像然后通過這個鏡像在啟動實體,然后就會給這個啟動的實體添加一層可讀寫的檔案系統,目前 Docker 的資料型別分為兩種, 一是資料卷, 二是資料容器,資料卷類似于掛載的一塊磁盤,資料容器是將資料保存在一個容器上

- 查看指定 PID 的容器資訊
docker inspect f55c55544e05

LowerDir: image 鏡像層(鏡像本身,只讀)
UpperDir:容器的上層(讀寫)
MergedDir:容器的檔案系統,使用 Union FS(聯合檔案系統)將 lowerdir 和
WorkDir:容器在 宿主機的作業目錄
什么是資料卷(data volume):
資料卷實際上就是宿主機上的目錄或者是檔案,可以被直接 mount 到容器當中使用,
實際生成環境中,需要針對不同型別的服務、 不同型別的資料存盤要求做相應的規劃, 最終保證服務的可擴展性、 穩定性以及資料的安全性,
如下圖:

左側是無狀態的 http 請求服務, 右側為有狀態,
下層為不需要存盤的服務,上層為需要存盤的部分服務
創建 APP 目錄并生成 web 頁面:
此 app 以資料卷的方式,提供給容器使用, 比如容器可以直接宿主機本地的 web_app,而需要將代碼提前添加到容器中,此方式適用于小型 web 站點,
mkdir /data/testapp –p
echo "testapp page" > /data/testapp/index.html
在宿主機或容器修改資料
- 給目錄下添加index檔案
mkdir /data/app
echo "docker volume Pages1" > /data/app/index.html
啟動容器并驗證資料:
啟動兩個容器, web1 容器和 web2 容器, 分別測驗能否在容器內訪問到宿主機的添加的資料,
注意使用 -v 引數, 將宿主機目錄映射到容器內部, web2 的 ro 標示在容器內對該目錄只讀,默認是可讀寫的:
docker run -d --name web1 -v /data/app/:/usr/share/nginx/html -p 85:80 nginx
docker run -d --name web2 -v /data/app/:/usr/share/nginx/html:ro -p 86:80 nginx
2、web 界面訪問(這里使用命令列測驗)

3、洗掉容器
洗掉容器的時候指定引數-v, 可以洗掉/var/lib/docker/containers/的容器資料目錄,但是不會洗掉資料卷的內容
docker rm -fv d044730c0f4f
資料卷的特點及使用:
1、資料卷是宿主機的目錄或者檔案,并且可以在多個容器之間共同使用,
2、 在宿主機對資料卷更改資料后會在所有容器里面會立即更新,
3、資料卷的資料可以持久保存,即使洗掉使用使用該容器卷的容器也不影響,
4、 在容器里面的寫入資料不會影響到鏡像本身,檔案掛載:
檔案掛載用于很少更改檔案內容的場景, 比如 nginx 的組態檔、 tomcat 的組態檔等
資料卷使用場景:
1、 日志輸出
2、 靜態 web 頁面
3、 應用組態檔
4、 多容器間目錄或檔案共享
如何一次掛載多個目錄
- 多個目錄可以位于不同的目錄下
mkdir /data/xuecho "xu" > /data/xu/index.html
- 啟動容器
docker run -ti -d --name web1 -p 85:80 \
-v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /data/nginx/:/usr/share/nginx/html \
nginx
3. 驗證 web 訪問
資料卷容器:
資料卷容器功能是可以讓資料在多個 docker 容器之間共享,即可以讓 B 容器訪問 A 容器的內容,而容器 C 也可以訪問 A 容器的內容,\
即先要創建一個后臺運行的容器作為 Server,用于卷提供, 這個卷可以為其他容器提供資料存盤服務,其他使用此卷的容器作為 client 端:
啟動一個卷容器 Server:
先啟動一個容器, 并掛載宿主機的資料目錄:
將宿主機的 catalina.sh 啟動腳本和 chen 的 web 頁面,分別掛載到卷容器 server端,然后通過 server 端共享給 client 端使用,
docker run -d --name volume-server \
-v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /data/nginx:/usr/share/nginx/html \
nginx
- 啟動兩個端容器 Client
docker run -d --name web1 -p 85:80 \
--volumes-from volume-server nginx
docker run -d --name web2 -p 86:80 \
--volumes-from volume-server nginx
- 其實實質就是把掛載在其它容器的卷,再掛到其它容器上
docker run -d --name web3 -p 83:80 \ --volumes-from web2 nginx
- 測驗訪問 web 頁面
三個容器訪問到的資料是一樣的
-
進入其它一個容器,修改網站的默認測驗頁面
docker exec -it 85466a0c2fda bash
5. 驗證宿主機資料
# cat /data/nginx/index.html 3333
- 關閉卷容器 Server 測驗能否啟動新容器:
docker stop volume-server docker run -d --name web6 -p 86:80 \ --volumes-from volume-server nginx
停止了卷服務的容器,還可以從這個卷服務容器啟動新的容器
- 測驗洗掉源卷容器 Server 創建容器
docker rm -fv volume-server
[root@Server1 ~]# docker run -d --name web7 -p 87:80 --volumes-from volume-server nginx
docker: Error response from daemon: No such container: volume-server.
# 這里就不行了,報錯
- 測驗之前的容器是否正常——已經運行的容器不受任何影響
之前已啟動的容器不受影響
重新創建容器卷 Server
docker run -d --name volume-server \ -v /data/app/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /data/nginx:/usr/share/nginx/html \ nginx
創建出 volume server 之后, 就可以創建基于 volume server 的新容器,
docker run -d --name web8 -p 88:80 \ --volumes-from volume-server nginx
在當前環境下, 即使把提供卷的容器 Server 洗掉, 已經運行的容器 Client 依然可以使用掛載的卷, 因為容器是通過掛載訪問資料的, 但是無法創建新的卷容器客戶端, 但是再把卷容器 Server 創建后即可正常創建卷容器 Client,
此方式可以用于線上共享資料目錄等環境, 因為即使資料卷容器被洗掉了,其他已經運行的容器依然可以掛載使用
資料卷容器可以作為共享的方式為其他容器提供檔案共享,類似于 NFS 共享,可以在生產中啟動一個實體掛載本地的目錄,然后其他的容器分別掛載此容器的目錄,即可保證各容器之間的資料一致性,
十五:
主要介紹docker網路相關知識,docker服務安裝完成之后,至少在每個主機機會生成一個名稱為docker0的網卡
其IP地址都是172.17.0.1/16,并且會生成某種不同型別的網路,如下圖:
docker結合負載實作網站高可用:
整體規劃圖:
下圖為一個小型的網路架構圖,其中nginx使用docker運行

| 服務器名 | 系統 | ip |
|---|---|---|
| 服務器1 | centos 7.6 | 192.168.99.101 |
| 服務器2 | centos 7.6 | 192.168.99.102 |
| 碼頭工人1 | Ubuntu的04.04 | 192.168.99.22 |
| 碼頭工人2 | Ubuntu的04.04 | 192.168.99.23 |
1.安裝并配置keepalived
- Server1安裝
yum install keepalived haproxy -y vim /etc/keepalived/keepalived.conf ... ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from root@localhost smtp_server localhost smtp_connect_timeout 30 router_id LVS_DEVEL1 vrrp_skip_check_adv_addr #vrrp_strict vrrp_iptables vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance MAKE_VIP_INT { state MASTER interface eth0 virtual_router_id 1 priority 100 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.99.10 dev eth0 label eth0:1 } }
啟動
systemctl restart keepalived
systemctl enable keepalived
- Server2安裝
yum install keepalived haproxy –y
配置
vim /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from root@localhost smtp_server localhost smtp_connect_timeout 30 router_id LVS_DEVEL2 vrrp_skip_check_adv_addr #vrrp_strict vrrp_iptables vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance MAKE_VIP_INT { state BACKUP interface eth0 virtual_router_id 1 priority 50 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.99.10 dev eth0 label eth0:1 } }
啟動
systemctl restart keepalived
systemctl enable keepalived
2.安裝并配置haproxy
- 各服務器配置內核引數
echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf sysctl -p
- Server1配置haproxy
vim /etc/haproxy/haproxy.cfg global maxconn 100000 uid 99 gid 99 daemon nbproc 1 log 127.0.0.1 local0 info defaults option http-keep-alive #option forwardfor maxconn 100000 mode tcp timeout connect 500000ms timeout client 500000ms timeout server 500000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys #================================================================ frontend docker_nginx_web bind 0.0.0.0:80 mode http default_backend docker_nginx_hosts backend docker_nginx_hosts mode http balance roundrobin server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5 server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5啟動haproxy
systemctl enable haproxy
systemctl restart haproxy
- Server2配置haproxy
vim /etc/haproxy/haproxy.cfg global maxconn 100000 uid 99 gid 99 daemon nbproc 1 log 127.0.0.1 local0 info defaults option http-keep-alive #option forwardfor maxconn 100000 mode tcp timeout connect 500000ms timeout client 500000ms timeout server 500000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys #================================================================ frontend docker_nginx_web bind 0.0.0.0:80 mode http default_backend docker_nginx_hosts backend docker_nginx_hosts mode http balance roundrobin server 192.168.99.22 192.168.99.22:81 check inter 2000 fall 3 rise 5 server 192.168.99.23 192.168.99.23:81 check inter 2000 fall 3 rise 5啟動haproxy
systemctl enable haproxy
systemctl restart haproxy
3. docker服務器啟動nginx容器并驗證
- dcoekr1啟動Nginx容器
docker1:192.168.99.22
# 先下載nginx鏡像
docker pull nginx docker run --name nginx-web1 -d -p 81:80 nginx
驗證網路訪問

- docker2啟動nginx容器
docker2:192.168.99.23
# 先下載nginx鏡像
docker pull nginx docker run --name nginx-web1 -d -p 81:80 nginx
驗證網路訪問

- 訪問VIP
-
Server1 haproxy狀態頁面:192.168.99.101:9999 / haproxy-status

-
Server2 haproxy狀態頁面:192.168.99.102:9999 / haproxy-status

容器之間的互聯
通過容器名稱互聯:
即在同一個主機上的容器之間可以通過自定義的容器名稱相互訪問,某個業務前端靜態頁面是使用nginx,動態頁面使用的是tomcat,由于容器在啟動的時候其內部IP地址是DHCP隨機分配的,所以如果通過內部訪問的話,自定義名稱是相對比較固定的,因此比較適用于此場景,
- 先創建第一個容器,后續會使用到這個容器的名稱:
docker run -it -d --name app1 -p 88:80 nginx
- 查看當前主機檔案內容
[root@Server1 ~]# docker exec -it app1 bash root@260fea18537b:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 260fea18537b
- 創建第二個容器
docker run -it -d -p 89:80 --name app2 --link app1 nginx
- 查看第二個容器的主機檔案內容
[root@Server1 ~]# docker exec -it app2 bash root@cd11e8d1d51e:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 app1 260fea18537b ## 連接的對方容器的 ID 和容器名稱
172.17.0.3 cd11e8d1d51e
- 檢測通信
ping app1
可能需要先安裝ping工具
apt-get update && apt install -y iputils-ping

通過自定義容器別名互聯:
上一步驟中,自定義的容器名稱可能后期會發生變化,那么一旦名稱發生變化,程式之間也要隨之發生變化,此類程式通過容器名稱進行服務呼叫,但是容器名稱發生變化之后再使用之前的名稱肯定是無法成功呼叫,每次都進行更改的話又比較麻煩,因此可以使用自定義別名的方式解決,即容器名稱可以隨意更容易,只要不更改別名即可,具體如下:
命令格式:
docker run -d --name 新容器名稱 \
--link 目標容器名稱:自定義的名稱 \
-p 本地埠:容器埠 鏡像名稱 shell命令
- 啟動第三個容器
docker run -it -d -p 90:80 --name app3 --link app1:web1 nginx
- 查看當前容器的主機
[root@Server1 ~]# docker exec -it app3 bash
root@9b99ad938dbe:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 web1 260fea18537b app1 # 多了一個別名web1
172.17.0.4 9b99ad938dbe
- 檢查自定義別名通信
ping web1
-
docker網路型別:
docker的網路使用docker network ls命令看到有一種型別,下面將介紹每一種型別的具體作業方式:
使用引數–net=網路型別指定,而不指定替代就是bridge模式,
查看當前docke的網卡資訊:
docker network list
網橋:可以,使用自定義IP
主機:不獲取IP直接使用物理機IP,并監聽物理機IP監聽埠
無:沒有網路
(1)主機模式:使用引數–net = host指定,
啟動的容器如果指定了使用主機模式,那么新創建的容器不會創建自己的虛擬網卡,而是直接使用托管機的網卡和IP地址,因此在容器里面查看到的IP資訊就是宿主機的資訊,
訪問容器的時候直接使用主機機IP +容器埠即可,不過容器的其他資源他們必須檔案系統,系統行程等還是和主機保持隔離,模式的網路性能最高,但是各個容器之間的埠不能相同,適用于運行容器埠比較固定的業務,
- 為避免埠沖突,先洗掉所有的容器:
docker rm -fv `docker ps -a -q`
2. 啟動一個新容器,并指定網路模式為主機
docker run -d --name app1 --net=host nginx
3. 訪問
主機機驗證因為是主機模式,所以直接訪問主機機的IP:192.168.0.36
訪問到的是nginx的默認首頁
主機模式不支持埠映射,當指定埠映射的時候會提示如下警告資訊:
使用主機網路模式時,將替換已指定的埠
docker run -d --name app2 -p 81:80 --net=host nginx

(2)None模式:使用引數–net = none指定
在使用none模式后,Docker容器不會進行任何網路配置,其沒有網卡,沒有IP也沒有路由,因此無法與外部通信,需要手動添加網卡配置IP等,所以極少使用
命令使用方式:
docker run -it -d --name net_none -p 80:80 --net=none nginx
(3)容器模式:使用引數–net = container:name或ID
使用此模式創建的容器需要指定和一個已經存在的容器共享一個網路,而不是和容納機共享網,新創建的容器不會創建自己的網卡也不會配置自己的IP,或者和一個已經存在的被指定的容器IP和埠范圍,
因此該容器的埠不能和被指定的埠沖突,除了網路之外的檔案系統,進展資訊等仍保持相互隔離,兩個容器的進展可以通過lo網卡及容器IP進行通信,
- 先起一個容器
docker run -it -d --name app11 -p 7070:8080 nginx
- 另一個容器直接使用對方的網路
docker run -it -d --name app12 --net=container:app11 tomcat85-app1:v1
- nginx的默認埠為80,而8080是tomcat的默認埠,所以,如果我們直接訪問托宿主機的7070,應該是訪問到tomcat的頁面才對,如圖

(4)bridge模式: docker的交替模式即不指定任何模式就是bridge模式,也是使用比較多的模式,此模式創建的容器會為每一個容器分配自己的網路IP等資訊,且多個容器連接到一個虛擬網橋與外界通信 
查看bridge模式的資訊
docker network inspect bridge

docker跨主機互聯之簡單實作:
跨主機互聯是說A主機的容器可以訪問B主機上的容器,但是可以保證各主機之間的網路是可以相互通信的,然后各容器才可以通過主機訪問到對方的容器,實作原理是在主機做一個網路路由就可以實作A主機的容器訪問B主機的容器的目的,
復雜的網路或者大型的網路可以使用google開源的k8s進行互聯,
修改各主機機網段: Docker的替代網段是172.17.0.x / 24,而且每個主機機都是一樣的,因此路由選擇的路由就是各個主機的網路不能一致,具體如下:
服務器A:192.168.0.36
服務器B:192.168.0.59
- 服務器A更改網段
vim /lib/systemd/system/docker.service
在ExecStart結尾追加--bip=10.10.0.1/24,ip是你想設定的網路的網關ip
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
- 重啟docker服務
systemctl daemon-reload
systemctl restart docker
- 驗證一個服務器網卡
ifconfig docker0

如果你的系統是Centos,需要打開ipforward
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p
- 啟動一個容器
docker run -it -p 87:80 nginx bash [root@781e7f053c20 /]# ifconfig eth0

- 添加靜態路由(主機上)
route add -net 10.10.0.0/24 gw 192.168.0.59
iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT
- 服務器B更改網段
vim /lib/systemd/system/docker.service
在ExecStart結尾追加--bip=10.20.0.1/24,注意不能跟服務器A一樣
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24
- 重啟docker服務
systemctl daemon-reload
systemctl restart docker
- 驗證網卡: ifconfig docker0

- 如果你的系統是Centos,需要打開ipforward規則轉發
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p
- 啟動一個容器
docker run -it -p 82:80 nginx bash
[root@781e7f053c20 /]# ifconfig eth0
- 添加靜態路由
route add -net 10.10.0.0/24 gw 192.168.0.36
iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT

容器間互相ping測驗
互連兩臺服務器分別啟動兩個容器進行測驗:10.10.0.0網段是服務器A內的容器,10.20.0.0網段是服務器B內的容器
在另一臺容器里反ping試一下

如果可以ping通就表示沒有問題,兩個不同宿主機上的容器可以互相通信了
創建自定義網路:
可以基于docker命令創建自定義網路,自定義網路可以自定義IP地域和網關等資訊,
幫助
docker network create –help
- 創建自定義docker網路
docker network create -d bridge --subnet 10.100.0.0/24 \
--gateway 10.100.0.1 my-net
- 查看網路
docker network list

- 使用自定義網路創建容器
[root@Server1 ~]# docker run -itd --net=my-net centos-nginx:v1 bash
[root@Server1 ~]# docker exec -it 25d2c84d58bd bash
[root@25d2c84d58bd /]# yum install -y net-tools &> /dev/null
[root@25d2c84d58bd /]# ifconfig eth0

- 創建默認網路容器
docker run -it centos-nginx:v1 bash
[root@ed06c2785c92 /]# ifconfig eth0 [root@ed06c2785c92 /]# ping www.baidu.com
- 如何與使用交替網路的容器通信:
現在有一個docker0(10.10.0.0/24)網路一個自定義的my-net(10.100.0.0/24)網路,每個網路上分別運行了不同數量的容器,那么怎么才能讓位于不同網路的容器可以相互通信呢? 那就是修改防火墻規則條目 -
保存下iptbales
iptables-save > iptables.sh
- 修改iptables.sh
# vim iptables.sh

把DOCKER-ISOLATION-STAGE-2除了RETURN結尾的都注釋了
- 重新匯入修改后的iptables規則
iptables-restore < iptables.sh
4. 驗證通信
先看一下其他網段的容器ip地址

ping測驗一下

經過以上的配置,目前就已經實作了不通網路間的通信
十六、Docker資源限制
官網:https://docs.docker.com/config/containers/resource_constraints/
默認情況下, 容器沒有資源限制, 可以使用主機內核調度程式允許的盡可能多的給定資源, Docker 提供了控制容器可以限制容器使用多少記憶體或 CPU 的方法,設定 docker run 命令的運行時配置標志,
其中許多功能都要求宿主機的內核支持 Linux 功能, 要檢查支持, 可以使用docker info 命令,如果內核中禁用了某項功能, 可能會在輸出結尾處看到警告,
如下所示:
WARNING: No swap limit support
對于 Linux 主機, 如果沒有足夠的內容來執行其他重要的系統任務, 將會拋出OOM (Out of Memory Exception,記憶體溢位、 記憶體泄漏、 記憶體例外), 隨后系統會開始殺死行程以釋放記憶體, 凡是運行在宿主機的行程都有可能被 kill, 包括 Dockerd和其它的應用程式, 如果重要的系統行程被 Kill,會導致和該行程相關的服務全部宕機,
產生 OOM 例外時, Dockerd 嘗試通過調整 Docker 守護程式上的 OOM 優先級來減輕這些風險,以便它比系統上的其他行程更不可能被殺死,但是容器的 OOM優先級未調整, 這使得單個容器被殺死的可能性比 Docker 守護程式或其他系統行程被殺死的可能性更大,不推薦通過在守護程式或容器上手動設定--oomscore-adj 為極端負數,或通過在容器上設定--oom-kill-disable 來繞過這些安全措施,
OOM 優先級機制:
linux 會為每個行程算一個分數,最終他會將分數最高的行程 kill,
/proc/PID/oom_score_adj:范圍為-1000 到 1000,值越高越容易被宿主機 kill掉,如果將該值設定為-1000,則行程永遠不會被宿主機 kernel kill,
/proc/PID/oom_adj:范圍為-17 到+15,取值越高越容易被干掉,如果是-17,則表示不能被 kill,該設定引數的存在是為了和舊版本的 Linux 內核兼容,
/proc/PID/oom_score:這個值是系統綜合行程的記憶體消耗量、 CPU 時間(utime + stime)、存活時間(uptime - start time)和 oom_adj 計算出的,消耗記憶體越多分越高,存活時間越長分越低,
容器的記憶體限制:
Docker 可以強制執行硬性記憶體限制,即只允許容器使用給定的記憶體大小,
Docker 也可以執行非硬性記憶體限制,即容器可以使用盡可能多的記憶體,除非內核檢測到主機上的記憶體不夠用了,
--oom-score-adj: 宿主機 kernel 對行程使用的記憶體進行評分, 評分最高的將被宿主機內核 kill 掉, 可以指定一個容器的評分制但是不推薦手動指定,
--oom-kill-disable: 對某個容器關閉 oom 機制,
記憶體限制引數:
-m, --memory:容器可以使用的最大記憶體量,如果設定此選項,則允許的最記憶體值為 4m (4 兆位元組),
--memory-swap: 容器可以使用的交換磁區大小, 必須要在設定了物理記憶體限制的前提才能設定交換磁區的限制
--memory-swappiness: 設定容器使用交換磁區的傾向性,值越高表示越傾向于使用 swap 磁區,范圍為 0-100, 0 為能不用就不用, 100 為能用就用,
--kernel-memory: 容器可以使用的最大內核記憶體量,最小為 4m,由于內核記憶體與用戶空間記憶體隔離,因此無法與用戶空間記憶體直接交換,因此內核記憶體不足的容器可能會阻塞宿主主機資源,這會對主機和其他容器或者其他服務行程產生影響,因此不要設定內核記憶體大小,
--memory-reservation:允許指定小于--memory 的軟限制,當 Docker 檢測到主機上的爭用或記憶體不足時會激活該限制,如果使用--memory-reservation,則必須將其設定為低于--memory 才能使其優先, 因為它是軟限制,所以不能保證容器不超過限制,
--oom-kill-disable 默認情況下,發生 OOM 時, kernel 會殺死容器內行程,但是可以使用--oom-kill-disable 引數,可以禁止 oom 發生在指定的容器上,即 僅在已設定-m選項的容器上禁用 OOM,如果-m 引數未配置,產生 OOM 時,主機為了釋放記憶體還會殺死系統行程,
swap 限制:
--memory-swap:只有在設定了 --memory 后才會有意義,使用 Swap,可以讓容器將超出限制部分的記憶體置換到磁盤上, WARNING:經常將記憶體交換到磁盤的應用程式會降低性能,
不同 --memory-swap 的設定會產生不同的效果:
值為正數, 那么--memory 和--memory-swap 都必須要設定,--memory-swap表示你能使用的記憶體和 swap 磁區大小的總和,例如:--memory=300m,--memory-swap=1g, 那么該容器能夠使用 300m 記憶體和 700m swap,即--memory是實際物理記憶體大小值不變,而 swap 的實際大小計算方式為
(--memory-swap)-(--memory)=容器可用 swap(??memory?swap)?(??memory)=容器可用swap,如果設定為 0:則忽略該設定,并將該值視為未設定,即未設定交換磁區,
如果等于--memory 的值,并且--memory 設定為正整數: 容器無權訪問 swap 即也沒有設定交換磁區,
如果設定為 unset:如果宿主機開啟了 swap,則實際容器的swap 值為 2x( --memory),即兩倍于物理記憶體大小,但是并不準確(在容器中使用free 命令所看到的 swap 空間并不精確, 畢竟每個容器都可以看到具體大小,但是宿主機的 swap 是有上限而且不是所有容器看到的累計大小),
如果設定為-1:如果宿主機開啟了 swap,則容器可以使用主機上 swap 的最大空間,
動態修改容器記憶體,先計算出所需要的記憶體的位元組數:如268435456(256M),只能調大不能調小
echo "268435456" > /sys/fs/cgroup/memory/docker/9fa20d824b18.../memory.limit_in_bytes
9fa20d824b18... 是容器ID
記憶體限制驗證:
假如一個容器未做記憶體使用限制, 則該容器可以利用到系統記憶體最大空間, 默認創建的容器沒有做記憶體資源限制,
#測驗鏡像
docker pull lorel/docker-stress-ng
查看幫助
apt install stress-ng
stress-ng --help
或者這樣也行
docker run -it --rm lorel/docker-stress-ng -help
記憶體大小硬限制
查看docker狀態
docker stats
- 啟動兩個作業行程,每個作業行程最大允許使用記憶體 256M,且宿主機不限制當前容器最大記憶體:
docker run -it --rm --name c1 lorel/docker-stress-ng \ --vm 2 --vm-bytes 256M
--vm 啟動多少個行程
--vm-bytes 為每個行程分配的記憶體
- 宿主機限制容器最大記憶體使用:
docker run -it --rm -m 256m --name c2 lorel/docker-stress-ng \
--vm 2 --vm-bytes 256M
- 宿主機 cgroup 驗證:
# cat /sys/fs/cgroup/memory/docker/容器 ID /memory.limit_in_bytes
268435456
宿主機基于 cgroup 對容器進行記憶體資源的大小限制
注:通過 echo 命令可以改記憶體限制的值,但是可以在原基礎之上增大記憶體限制,縮小記憶體限制會報錯 write error: Device or resource busy
記憶體大小軟限制:
docker run -it --rm -m 256m --memory-reservation 128m \
--name c3 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
- 宿主機 cgroup 驗證:
# cat /sys/fs/cgroup/memory/docker/容器 ID/memory.soft_limit_in_bytes
134217728
回傳的軟限制結果
關閉 OOM 機制
docker run -it --rm -m 256m --oom-kill-disable \
--name c4 lorel/dockerstress-ng --vm 2 --vm-bytes 256M
# cat /sys/fs/cgroup/memory/docker/容器 ID/memory.oom_control
oom_kill_disable 1
under_oom 1
oom_kill 0
交換磁區限制
docker run -it --rm -m 256m --memory-swap 512m \
--name magedu-c1 centos bash
宿主機 cgroup 驗證:
# cat /sys/fs/cgroup/memory/docker/容器 ID/memory.memsw.limit_in_bytes
536870912
容器的 CPU 限制
一個宿主機,有幾十個核心的 CPU, 但是宿主機上可以同時運行成百上千個不同的行程用以處理不同的任務, 多行程共用一個 CPU 的核心依賴計數就是為可壓縮資源, 即一個核心的 CPU 可以通過調度而運行多個行程, 但是同一個單位時間內只能有一個行程在 CPU 上運行, 那么這么多的行程怎么在 CPU 上執行和調度的呢?
實時優先級: 0 - 99
非實時優先級(nice): -20 - 19, 對應 100 - 139 的行程優先級
Linux kernel 行程的調度基于 CFS(Completely Fair Scheduler), 完全公平調度
CPU 密集型的場景:優先級越低越好, 計算密集型任務的特點是要進行大量的計算,消耗 CPU 資源,比如計算圓周率、 資料處理、 對視頻進行高清解碼等等,全靠 CPU 的運算能力,
IO 密集型的場景:優先級值高點, 涉及到網路、磁盤 IO 的任務都是 IO 密集型任務,這類任務的特點是 CPU 消耗很少,任務的大部分時間都在等待 IO 操作完成(因為 IO 的速度遠遠低于 CPU 和記憶體的速度),比如 Web 應用, 高并發,資料量大的動態網站來說,資料庫應該為 IO 密集型,
磁盤的調度演算法
# cat /sys/block/sda/queue/scheduler
noop deadline [cfq]
默認情況下,每個容器對主機 CPU 周期的訪問權限是不受限制的, 但是我們可以設定各種約束來限制給定容器訪問主機的 CPU 周期,大多數用戶使用的是默認的 CFS 調度方式, 在 Docker 1.13 及更高版本中, 還可以配置實時優先級,
引數:
--cpus :指定容器可以使用多少可用 CPU 資源, 例如,如果主機有兩個 CPU,并且設定了--cpus =“1.5”,那么該容器將保證最多可以訪問 1.5 個的 CPU(如果是 4 核 CPU, 那么還可以是 4 核心上每核用一點,但是總計是 1.5 核心的CPU), 這相當于設定--cpu-period =“100000”和--cpu-quota =“150000”
主要在 Docker 1.13 和更高版本中使用, 目的是替代--cpu-period 和--cpuquota 兩個引數,從而使配置更簡單, 最大不能超出宿主機的 CPU 總核心數(在作業系統看到的 CPU 超執行緒后的數值),
分配給容器的 CPU 超出了宿主機 CPU 總數,
# docker run -it --rm --cpus 2 centos bash
docker: Error response from daemon: Range of CPUs is from 0.01 to 1.00, as there are only 1 CPUs available.
See 'docker run --help'.
--cpu-period:(CPU 調度周期)設定 CPU 的 CFS 調度程式周期,必須與
--cpuquota一起使用,默認周期為 100 微秒
--cpu-quota: 在容器上添加 CPU CFS 配額, 計算方式為cpu-quota/cpu-period的結果值, 早期的 docker(1.12 及之前)使用此方式設定對容器的 CPU 限制值,==新版本 docker(1.13 及以上版本)通常使用--cpus 設定此值,==--cpuset-cpus:用于指定容器運行的 CPU 編號,也就是我們所謂的綁核,
--cpuset-mem:設定使用哪個 cpu 的記憶體,僅對 非統一記憶體訪問(NUMA)架構有效,
--cpu-shares:用于設定 cfs 中調度的相對最大比例權重,cpu-share 的值越高的容器,將會分得更多的時間片(宿主機多核 CPU 總數為 100%, 假如容器 A 為1024, 容器 B 為 2048, 那么容器 B 將最大是容器 A 的可用 CPU 的兩倍 ),默認的時間片 1024,最大 262144,
測驗 CPU 限制
- 未限制容器 CPU
對于一臺四核的服務器,如果不做限制, 容器會把宿主機的 CPU 全部占完,
分配 4 核 CPU 并啟動 4 個作業執行緒
docker run -it --rm --name c10 lorel/docker-stress-ng \
--cpu 4 --vm 4
在宿主機使用 dokcer top 命令查看容器運行狀態
docker top CONTAINER [ps OPTIONS]
容器運行狀態:
docker stats
在宿主機查看 CPU 限制引數:
# cat /sys/fs/cgroup/cpuset/docker/${容器ID}/cpuset.cpus
0-3
- 限制容器 CPU
只給容器分配最多兩核宿主機 CPU 利用率
docker run -it --rm --name c11 \
--cpus 2 lorel/docker-stress-ng --cpu 4 --vm 4
宿主機 cgroup 驗證
# cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.cfs_quota_us 200000
每核心 CPU 會按照 1000 為單位轉換成百分比進行資源劃分, 2 個核心的 CPU 就是 200000/1000=200%, 4 個核心 400000/1000=400%,以此類推
宿主機 CPU 利用率
- 將容器運行到指定的 CPU 上
docker run -it --rm --name c12 --cpus 1 \ --cpuset-cpus 1,3 lorel/docker-stress-ng --cpu 2 --vm 2 # cat /sys/fs/cgroup/cpuset/docker/容器 ID /cpuset.cpus 1,3
容器運行狀態
docker stats
- 基于 cpu—shares 對 CPU 進行切分
啟動兩個容器, c13 的--cpu-shares值為 1000, c14 的--cpu-shares為 500, 觀察最終效果,--cpu-shares值為 1000 的 c13 的 CPU 利用率基本是--cpu-shares為 500 的 c14 的兩倍:
docker run -it --rm --name c13 --cpu-shares 10 \
lorel/docker-stress-ng --cpu 1 --vm 2
docker run -it --rm --name c14 --cpu-shares 5 \
lorel/docker-stress-ng --cpu 1 --vm 2
驗證容器運行狀態
docker stats
宿主機 cgroup 驗證
# cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
1000
# cat /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
500
- 動態修改 CPU shares 值:
--cpu-shares的值可以在宿主機 cgroup 動態修改, 修改完成后立即生效,其值可以調大也可以減小,
echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/容器 ID/cpu.shares
驗證修改后的容器運行狀態 docker stats
十七
單機編排之Docker撰寫:
當在主機啟動主機的容器時候,如果都是手動操作會覺得比較麻煩而且容器出錯,這個時候推薦使用docker單機編排工具docker-compose,docker-compose是docker容器的一種單機編排服務,docker- compose是一個管理多個容器的工具,可以解決容器之間的依賴關系,就像啟動一個nginx前端服務的時候會呼叫后端的tomcat,那就得先啟動tomcat,但是啟動tomcat容器還需要依賴資料庫,則那就還得先啟動資料庫,docker-compose就可以解決這樣的嵌套依賴關系,其完全可以替代docker run對容器進行創建,啟動和停止,
docker-compose專案是Docker官方的開源專案,負責實作對Docker容器放置的快速編排,docker-compose將所管理的容器分為三層,分別是工程(專案),服務以及容器
github地址https://github.com/docker/compose
基礎環境準備:
服務器1 :192.168.99.21,港口服務器2:192.168.99.22,
docker -compose 下面開始在服務器1上安裝harbor和創建nginx,tomcat,haproxy大量備用

配置安裝港口:
- 下載Harbor離線安裝包:
cd /usr/local/src/ wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.5.tgz
- 解壓
tar xf harbor-offline-installer-v1.7.5.tgz ln -sv /usr/local/src/harbor /usr/local/
- 下載docker-compose
Ubuntu:
apt update apt install -y python-pip pip install docker-compose
中心:
yum install epel-release yum install -y python-pip pip install --upgrade pip pip install docker-compose
- 修改組態檔,最終配置如下
# vim harbor.cfg ... hostname = 192.168.99.22 ... harbor_admin_password = root123 ...
- 安裝
./install.sh
- 編輯docker組態檔:
注意:如果我們配置的是https的話,本地docker就不需要任何任何操作就可以訪問Harbor了
vim /lib/systemd/system/docker.service 在ExecStart追加 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.99.21
其中192.168.99.21是我們部署Harbor的地址,即hostname配置項值,配置完后需要重啟docker服務,
![]()
- 重啟docker服務:
systemctl daemon-reload
systemctl restart docker
- 重啟docker-compose
docker-compose restart
- 驗證能否登錄Harbor:
docker login 192.168.99.21
https://docs.docker.com/compose/reference/官方檔案
制作nginx鏡像
- 下載概述并初始化系統:
docker pull centos mkdir -pv /opt/dockerfile/web/nginx/html
- 撰寫Dockerfile:
cd /opt/dockerfile/web/nginx vim Dockerfile From centos:latest MAINTAINER han 123456@qq.com ADD nginx-1.10.3.tar.gz /usr/local/src/ RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm \ && yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop \ && cd /usr/local/src/nginx-1.10.3 \ && ./configure --prefix=/usr/local/nginx --with-http_sub_module \ && make \ && make install \ && cd /usr/local/nginx/ ADD nginx.conf /usr/local/nginx/conf/nginx.conf RUN useradd nginx -s /sbin/nologin \ && ln -sv /usr/local/nginx/sbin/nginx /usr/sbin/nginx \ && echo "test nginx page" > /usr/local/nginx/html/index.html EXPOSE 80 443 CMD ["nginx","-g","daemon off;"]
- 準備網頁
cd /opt/dockerfile/web/nginx/html echo "test nginx" > index.html cd /opt/dockerfile/web/nginx vim nginx.conf #user nobody; worker_processes 1; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /usr/local/nginx/html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
- 目錄如下
# cd .. # tree . . ├── Dockerfile ├── html │ └── index.html ├── nginx-1.10.3.tar.gz └── nginx.conf
- 構建鏡像
docker build -t mynginx:v1 /opt/dockerfile/web/nginx
- 查看是否生成新鏡像
docker images
- 從總體啟動容器
docker run --rm -p 81:80 --name nginx-web1 \
-v /opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/ \
-v /opt/dockerfile/web/nginx/nginx.conf:/usr/local/nginx/conf/nginx.conf \
mynginx:v1
- 訪問網路界面
-
打標簽:
docker tag mynginx:v1 192.168.99.21/nginx/mynginx:v1
-
在港口管理界面創建專案(需要先創建專案再上傳高層)

-
將向前推到港口:
docker push 192.168.99.21/nginx/mynginx:v1
- 發布完成

制作JDK環境
- 執行完善JDK的方針:
mkdir -p /opt/dockerfile/web/jdk cd /opt/dockerfile/web/jdk/
- 編輯Dockerfile
vim Dockerfile #JDK Base Image FROM centos:latest ADD jdk-8u211-linux-x64.tar.gz /usr/local/src/ RUN ln -sv /usr/local/src/jdk1.8.0_211 /usr/local/jdk ADD profile /etc/profile ENV JAVA_HOME /usr/local/jdk ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/ ENV PATH $PATH:$JAVA_HOME/bin RUN rm -rf /etc/localtime \ && ln -snf /usr/share/zoneinfo/Asia/Shanghai/etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone
- 準備環境變數檔案
vim profile
# /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge export JAVA_HOME=/usr/local/jdk export TOMCAT_HOME=/apps/tomcat export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$TOMCAT_HOME/bin:$PATH export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
看下目錄結構
# tree /opt/dockerfile/web/jdk /opt/dockerfile/web/jdk ├── Dockerfile ├── jdk-8u211-linux-x64.tar.gz └── profile
- 構建
cd /opt/dockerfile/web/jdk
docker build -t myjdk:v1 .
- 打標記
docker tag myjdk:v1 192.168.99.21/jdk/myjdk:v1
-
在港口頁面上創建jdk專案

-
將全面上傳到Harbor(以下有講)
docker push 192.168.99.21/jdk/myjdk:v1
從JDK整合重構tomcat
- 進入tomcat目錄:
mkdir -p /opt/dockerfile/web/tomcat cd /opt/dockerfile/web/tomcat
- 編輯Dockerfile檔案
vim Dockerfile FROM 192.168.99.21/jdk/myjdk:v1 RUN useradd www -u 2020 ENV TZ "Asia/Shanghai" ENV LANG en_US.UTF-8 ENV TERM xterm ENV TOMCAT_MAJOR_VERSION 8 ENV TOMCAT_MINOR_VERSION 8.0.49 ENV CATALINA_HOME /apps/tomcat ENV APP_DIR ${CATALINA_HOME}/webapps RUN mkdir /apps ADD apache-tomcat-8.5.45.tar.gz /apps RUN ln -sv /apps/apache-tomcat-8.5.45 /apps/tomcat
- 發布tomcat壓縮包:
apache-tomcat-8.5.45.tar.gz
tree /opt/dockerfile/web/tomcat /opt/dockerfile/web/tomcat ├── apache-tomcat-8.5.45.tar.gz └── Dockerfile
- 通過腳本構建tomcat基礎之上
docker build -t mytomcat:v1 .
- 驗證合并重建完成
docker images
- 進行打上標簽
docker tag mytomcat:v1 192.168.99.21/tomcat/mytomcat:v1
-
在港口頁面上創建tomcat專案

-
發布
docker push 192.168.99.21/tomcat/mytomcat
構建tomcat-app業務運營:
- 準備目錄
mkdir -pv /opt/dockerfile/web/tomcat-app cd /opt/dockerfile/web/tomcat-app
- 準備Dockerfile:
vim Dockerfile FROM 192.168.99.21/tomcat/mytomcat:v1 ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh ADD myapp/* /apps/tomcat/webapps/myapp/ RUN chown www.www /apps/ -R RUN chmod +x /apps/tomcat/bin/run_tomcat.sh EXPOSE 8080 8009 CMD ["/apps/tomcat/bin/run_tomcat.sh"]
- 準備自定義myapp頁面:
mkdir myapp echo "MyTomcat Web app Page1" > myapp/index.html
- 準備容器啟動執行腳本
run_tomcat.sh:
vim run_tomcat.sh #!/bin/bash echo "nameserver 223.5.5.5" > /etc/resolv.conf su - www -c "/apps/tomcat/bin/catalina.sh start" su - www -c "tail -f /etc/hosts"
- 檔案目錄
# tree . ├── Dockerfile ├── myapp │ └── index.html └── run_tomcat.sh
- 構建
docker build -t mytomcat-app:v1 .
- 查看鏡像
docker images
- 給Tomcat打標簽
docker tag mytomcat-app:v1 192.168.99.21/tomcat/mytomcat-app:v1
- 推送
docker push 192.168.99.21/tomcat/mytomcat-app:v1
制作haproxy補充:
- 進入目錄
mkdir -pv /opt/dockerfile/app/haproxy cd /opt/dockerfile/app/haproxy
- 準備Dockerfile:
vim Dockerfile #Haproxy Base Image FROM centos ADD haproxy-2.0.5.tar.gz /usr/local/src/ RUN yum -y install gcc gcc-c++ glibc glibc-devel pcre \ pcre-devel openssl openssl-devel systemd-devel \ net-tools vim iotop bc zip unzip zlib-devel lrzsz \ tree screen lsof tcpdump wget ntpdate \ && cd /usr/local/src/haproxy-2.0.5 \ && make ARCH=x86_64 TARGET=linux-glibc \ USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 \ USE_SYSTEMD=1 USE_CPU_AFFINITY=1 \ PREFIX=/usr/local/haproxy \ && make install PREFIX=/usr/local/haproxy \ && cp haproxy /usr/sbin/ \ && mkdir /usr/local/haproxy/run ADD haproxy.cfg /etc/haproxy/ ADD run_haproxy.sh /usr/bin RUN chmod +x /usr/bin/run_haproxy.sh EXPOSE 80 9999 CMD ["/usr/bin/run_haproxy.sh"]
- 準備
run_haproxy.sh腳本
vim run_haproxy.sh #!/bin/bash haproxy -f /etc/haproxy/haproxy.cfg tail -f /etc/hosts
- 準備
haproxy.cfg組態檔:
vim haproxy.cfg global chroot /usr/local/haproxy #stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin uid 99 gid 99 daemon nbproc 1 pidfile /usr/local/haproxy/run/haproxy.pid log 127.0.0.1 local3 info defaults option http-keep-alive option forwardfor mode http timeout connect 300000ms timeout client 300000ms timeout server 300000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys listen web_port bind 0.0.0.0:80 mode http log global balance roundrobin server web1 192.168.99.22:81 check inter 3000 fall 2 rise 5
調度到初步nginx服務的81埠
- 準備haproxy原始檔案:
haproxy-2.0.5.tar.gz
# tree /opt/dockerfile/app/haproxy
/opt/dockerfile/app/haproxy
├── Dockerfile
├── haproxy-2.0.5.tar.gz
├── haproxy.cfg
└── run_haproxy.sh
- 準備編制腳本:
docker build -t haproxy:v1 .
- 給通用打標簽
docker tag haproxy:v1 192.168.99.21/haproxy/haproxy:v1
- 港口創建haproxy專案
-
推送到倉庫
docker push 192.168.99.21/haproxy/haproxy:v1
從docker compose啟動臨時容器
換成server2繼續:
- 安裝docker-18.09.9
程序略 -
下載docker-compose
Ubuntu:
apt update apt install -y python-pip pip install docker-compose
Centos:
yum install epel-release yum install -y python-pip pip install --upgrade pip pip install docker-compose
- 驗證 docker-compose 版本
docker-compose -v
- 查看 docker-compose 幫助
docker-compose --help
- 編輯 docker 組態檔:
vim /lib/systemd/system/docker.service
在ExecStart追加
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.99.21
- 重啟 docker 服務:
systemctl daemon-reload
systemctl restart docker
- 測驗連接
docker login 192.168.99.21

- 創建網頁存放目錄,給容器掛載用
mkdir -pv /opt/dockerfile/web/nginx/html cd /opt/dockerfile/web/nginx/html echo "test nginx" > index.html
- 目錄可以在任意目錄, 推薦放在有意義的位置,如:
cd /opt/ mkdir docker-compose cd docker-compose
- 單個容器的 docker compose 檔案:
撰寫一個 yml 格式的配置 docker-compose 檔案, 啟動一個 nginx 服務
vim docker-compose.yml service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 expose: - 80 - 443 ports: - "80:80" - "443:443" volumes: - "/opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/"
service-nginx-web:服務名
image:鏡像名
container_name:容器名
expose:開放埠
post:宿主機映射埠
volume:資料卷掛載
- 啟動容器
docker-compose up -d
不加是 d 前臺啟動
![]()
- 啟動完成
# docker ps | grep nginx 1e453106ca9c 192.168.99.21/nginx/mynginx:v1 "nginx -g 'daemon of…" 49 seconds ago Up 47 seconds 443/tcp, 0.0.0.0:80->80/tcp
- 查看容器行程
docker-compose ps

- web 訪問測驗

啟動多個容器
docker pull 192.168.99.21/tomcat/mytomcat-app:v1
- 編輯組態檔
cd /opt/docker-compose/ vim docker-compose.yml service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 expose: - 80 - 443 ports: - "81:80" - "443:443" volumes: - "/opt/dockerfile/web/nginx/html/:/usr/local/nginx/html/" service-tomcat-app1: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app1 expose: - 8080 ports: - "8080:8080"
- 重啟容器
docker-compose stop
docker-compose up -d
- web 訪問測驗
-
重啟/停止/啟動單個指定容器
docker-compose restart/stop/start service-nginx-web
寫容器的 service 名稱,則是指定,
不指定則是所有
- 重啟所有容器:
docker-compose restart
實作Nginx反向代理Tomcat
創建nginx組態檔
- 創建nginx目錄
mkdir /opt/app mkdir -p nginx/html/app{1..2} cd /opt/app mkdir -p nginx/conf cd nginx/conf
- 創建nginx組態檔
vim nginx.conf #user nobody; worker_processes 1; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main 'remote_addr - remote_user [time_local] "request" ' # 'status body_bytes_sent "http_referer" '
# '"http_user_agent" "http_x_forwarded_for"';
# access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on; upstream tomcat_webserver {
server service-tomcat-app1:8080;
server service-tomcat-app2:8080;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /app1 {
root /apps/nginx/html;
index index.html index.htm;
}
location /app2 {
root /apps/nginx/html;
index index.html index.htm;
}
location /tomcat-app {
proxy_pass http://tomcat_webserver;
proxy_set_header Host host; proxy_set_header X-Forwarded-For proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP remote_addr; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
- 創建網頁
echo app111111 > /opt/app/nginx/html/app1/index.html echo app222222 > /opt/app/nginx/html/app2/index.html
創建haproxy組態檔
cd /opt/app mkdir -p haproxy/conf
vim ./haproxy/conf/haproxy.cfg
global chroot /usr/local/haproxy uid 99 gid 99 daemon nbproc 1 pidfile /usr/local/haproxy/run/haproxy.pid log 127.0.0.1 local3 info defaults option http-keep-alive option forwardfor mode http timeout connect 300000ms timeout client 300000ms timeout server 300000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth admin:123 listen web_port bind 0.0.0.0:80 mode http log global balance roundrobin server web1 nginx-web1:80 check inter 3000 fall 2 rise 5
nginx-web1:80 這里寫的是容器內部的埠,所以nginx容器開放的什么埠就寫多少,默認80,因為沒有對宿主機映射,所以可以不會埠沖突,
nginx-web1 是容器名
準備tomcat組態檔
cd /opt/app mkdir -p tomcat/conf
vim tomcat/conf/server.xml <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Note: A "Server" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/server.html --> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!-- Security listener. Documentation at /docs/config/listeners.html <Listener className="org.apache.catalina.security.SecurityListener" /> --> <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <!-- A "Service" is a collection of one or more "Connectors" that share a single "Container" Note: A "Service" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/service.html --> <Service name="Catalina"> <!--The connectors can use a shared executor, you can define one or more named thread pools--> <!-- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> --> <!-- A "Connector" represents an endpoint by which requests are received and responses are returned. Documentation at : Java HTTP Connector: /docs/config/http.html Java AJP Connector: /docs/config/ajp.html APR (HTTP/AJP) Connector: /docs/apr.html Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- A "Connector" using the shared thread pool--> <!-- <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 This connector uses the NIO implementation. The default SSLImplementation will depend on the presence of the APR/native library and the useOpenSSL attribute of the AprLifecycleListener. Either JSSE or OpenSSL style configuration may be used regardless of the SSLImplementation selected. JSSE style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2 This connector uses the APR/native implementation which always uses OpenSSL for TLS. Either JSSE or OpenSSL style configuration may be used. OpenSSL style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true" > <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> <SSLHostConfig> <Certificate certificateKeyFile="conf/localhost-rsa-key.pem" certificateFile="conf/localhost-rsa-cert.pem" certificateChainFile="conf/localhost-rsa-chain.pem" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- An Engine represents the entry point (within Catalina) that processes every request. The Engine implementation for Tomcat stand alone analyzes the HTTP headers included with the request, and passes them on to the appropriate Host (virtual host). Documentation at /docs/config/engine.html --> <!-- You should set jvmRoute to support load-balancing via AJP ie : <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> --> <Engine name="Catalina" defaultHost="localhost"> <!--For clustering, please take a look at documentation at: /docs/cluster-howto.html (simple how to) /docs/config/cluster.html (reference documentation) --> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="/data/tomcat/webapps/app" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> </Server>
- 準備tomcat動態頁面
cd /opt/app mkdir -p tomcat/app1/tomcat-app cd tomcat/app1/tomcat-app
注意這里:因為nginx中位置配置的配置路徑是tomcat-app,往tomcat調度的時候會帶上這個路徑,所以,掛載進去的路徑也要與之匹配,即:要能夠訪問http:// tomcat -app1:8080 / tomcat-app,才能通過nginx來調度
- 動態頁面示例
vim showhost.jsp <%@page import="java.util.Enumeration"%> <br /> host: <%try{out.println(""+java.net.InetAddress.getLocalHost().getHostName());}catch(Exception e){}%> <br /> remoteAddr: <%=request.getRemoteAddr()%> <br /> remoteHost: <%=request.getRemoteHost()%> <br /> sessionId: <%=request.getSession().getId()%> <br /> serverName:<%=request.getServerName()%> <br /> scheme:<%=request.getScheme()%> <br /> <%request.getSession().setAttribute("t1","t2");%> <% Enumeration en = request.getHeaderNames(); while(en.hasMoreElements()){ String hd = en.nextElement().toString(); out.println(hd+" : "+request.getHeader(hd)); out.println("<br />"); } %>
創建docker-compose.yml
mkdir -p /opt/app cd /opt/app vim docker-compose.yml service-haproxy: image: 192.168.99.21/haproxy/haproxy:v1 container_name: haproxy volumes: - ./haproxy/conf/haproxy.cfg:/etc/haproxy/haproxy.cfg expose: - 80 - 443 - 9999 ports: - "80:80" - "443:443" - "9999:9999" links: - service-nginx-web service-nginx-web: image: 192.168.99.21/nginx/mynginx:v1 container_name: nginx-web1 volumes: - ./nginx/html/app1:/apps/nginx/html/app1 - ./nginx/html/app2:/apps/nginx/html/app2 - ./nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf expose: - 80 - 443 links: - service-tomcat-app1 - service-tomcat-app2 service-tomcat-app1: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app1 volumes: - ./tomcat/app1:/data/tomcat/webapps/app/ROOT - ./tomcat/conf/server.xml:/apps/tomcat/conf/server.xml expose: - 8080 service-tomcat-app2: image: 192.168.99.21/tomcat/mytomcat-app:v1 container_name: tomcat-app2 volumes: - ./tomcat/app1:/data/tomcat/webapps/app/ROOT - ./tomcat/conf/server.xml:/apps/tomcat/conf/server.xml expose: - 8080
最終檔案目錄
cd /opt/app # tree . ├── docker-compose.yml ├── haproxy │ └── conf │ └── haproxy.cfg │ ├── nginx │ ├── conf │ │ └── nginx.conf │ └── html │ ├── app1 │ │ └── index.html │ └── app2 │ └── index.html └── tomcat ├── app1 │ └── tomcat-app │ └── showhost.jsp └── conf └── server.xml
測驗訪問
http://192.168.99.22/tomcat-app/showhost.jsp

以上就是Docke容器大部分的使用情景及功能實作
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/98098.html
標籤:Linux

