Docker 安裝使用實踐
文章目錄
安裝
MAC OS
現在在Mac上安裝Docker很簡單,brew
就可以。
brew cask install docker
貌似沒有裝cask
的,會自動初始化,直接執行上面的命令即可。支持macOS Sierra 10.12
以上系統。
也可以直接下載Stable或者Edge版本。dmg
文件,直接下載好安裝即可。
安裝的唯一問題是,可能會在
Updating Homebrew...
這個狀態等很久。搬了梯子也不行。找了一下資料,基本都是說更換brew源,而且看了好多頁面,都是更換到同一套,我也就直接用了。
cd "$(brew --repo)"
git remote set-url origin https://mirrors.ustc.edu.cn/brew.git
#替換homebrew-core.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git
brew update
# 備用地址-1
cd "$(brew --repo)"
git remote set-url origin https://git.coding.net/homebrew/homebrew.git
brew update
# 備用地址-2
cd "$(brew --repo)"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew-core.git
brew update
更新之後,也不算快,估計下載東西比較大。反正等着,自己執行完了。Applications
裏面就多了小鯨魚了。
不知道更換了源對其他安裝是否會有影響,如果有問題,就換回默認的:
#重置brew.git
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git
#重置homebrew-core.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git
上述配置內容,雖然我在很多頁面看到都一樣,但寫的比較認真的是從這裏
引用的。
centos
直接通過yum
安裝即可。
$ yum pudate
$ yum upgrade
$ yum install docker
可能都需要sudo
執行。
安裝完了啓動docker服務:
$ systemctl start docker
需要root密碼進行授權。
然後設置加速鏡像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://gbpursha.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
這樣安裝下來的是老版本,1.17什麼的。新的docker分成了ee和ce,而且版本都是17.xxx,18.xxx這樣了。安裝新版本:
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
rpm --import https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
yum -y install docker-ce
systemctl enable docker
systemctl restart docker
需要先把老的docker卸載掉。需要remove
掉:
yum remove docker
yum remove docker-common
新版本啓動之後,執行docker
命令,說.sock
沒權限。把當前用戶加入docker組:
sudo gpasswd -a ${USER} docker
升級docker之後,發現有些images沒法刪除。用root
用戶直接刪除:
/var/lib/docker/image/overlay2/imagedb/content/sha256
裏面的東西。把所有的鏡像都刪除。重新啓動docker服務。但有時候沒啥鳥用,直接卸載,刪除docker目錄,重新安裝。
安裝指定版本docker
sudo yum -y install --setopt=obsoletes=0 docker-ce-${version}
通過如下命令看可以安裝的版本:
yum list docker-ce.x86_64 --showduplicates
設置加速源
默認源pull
鏡像會想死。更換國內的加速源
https://gbpursha.mirror.aliyuncs.com
mac os從Preference直接加進去就行。
centos需要在/etc/docker/
中建立daemon.json
文件,加入如下內容:
{
"registry-mirrors": ["https://gbpursha.mirror.aliyuncs.com"]
}
然後重啓docker:
sudo systemctl restart docker
基本命令
mac的docker要用,需要在Applitions裏面先運行docker小鯨魚圖標。
先把幾個基礎命令搞清楚,分清楚鏡像、容器,怎麼安裝和運行。
- 拉取鏡像、安裝容器並且運行
$ docker run -d -p 80:80 --name webserver nginx
run
命令在指定鏡像第一次啓動的時候用,相當於執行了兩個步驟,將鏡像放入容器中(docker create),然後將容器啓動,使之變成運行時容器(docker start)。
執行run
命令,Docker 首先從本地主機上查找鏡像是否存在,如果不存在,Docker 就會從鏡像倉庫 Docker Hub 下載公共鏡像。
上述命令就是查找並安裝一個叫nginx
的鏡像,並且把nginx端口映射到80上。同時爲這個鏡像起名叫webserver
。
- 運行已經存在的容器
運行已經安裝好的容器,則使用:
$ docker start [CONTAINER ID]或者[NAMES]
需要知道容器的id或者名字。
- 拉取鏡像
docker pull httpd
或者其他的鏡像名字。pull
僅僅是從鏡像倉庫中把鏡像文件拉取到本地,並不會自動創建容器。
- 查看所有的容器命令如下:
$ docker ps -a
知道id或者名字就可以用start
命令來運行。
關於鏡像
Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建之後也不會被改變。
應該說,做鏡像文件應該是最難的事情。把自己的東西打包好做成鏡像。而且根據這個定義,鏡像文件是固定的,如果運行起來需要記錄文件等,需要指定到其他的位置(VOLUME
卷)。
Docker 官方維護了一個公共倉庫 Docker Hub。可以去註冊一個賬號,註冊了可以發佈自己的鏡像。
通過docker login
和docker logout
進行登錄和退出。
- 從官方倉庫中查找鏡像
想安裝一個鏡像,得知道都有哪些。執行如下命令,從官方倉庫中查找:
$ docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 5672 [OK]
ansible/centos7-ansible Ansible on Centos7 125 [OK]
jdeathe/centos-ssh OpenSSH / Supervisor / EPEL/IUS/SCL Repos - … 114 [OK]
consol/centos-xfce-vnc Centos container with "headless" VNC session… 100 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 64
imagine10255/centos6-lnmp-php56 centos6-lnmp-php56 57 [OK]
tutum/centos Simple CentOS docker image with SSH access 44
centos/postgresql-96-centos7 PostgreSQL is an advanced Object-Relational … 39
kinogmt/centos-ssh CentOS with SSH 29 [OK]
centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 26
pivotaldata/centos-gpdb-dev CentOS image for GPDB development. Tag names… 10
nathonfowlie/centos-jre Latest CentOS image with the JRE pre-install… 8 [OK]
drecom/centos-ruby centos ruby 6 [OK]
centos/tools Docker image that has systems administration… 4 [OK]
pivotaldata/centos Base centos, freshened up a little with a Do… 3
darksheer/centos Base Centos Image -- Updated hourly 3 [OK]
會有好多好多。看不出來能幹嘛。不如直接google
。
- 拉取鏡像
$ docker pull centos
Pulling repository centos
0b443ba03958: Download complete
前面說過,就是把鏡像拉到本地了。
- 從本地歸檔文件創建鏡像
已經後的鏡像的歸檔文件在本地了,通過import
命令創建鏡像。
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
參數:
-c :應用docker 指令創建鏡像;
-m :提交時的說明文字;
比如:
$ docker import my_ubuntu_v3.tar runoob/ubuntu:v4
- 查看本地鏡像
$ docker image ls
ls
後面可以帶通配符過濾。或者:
$ docker images
- 刪除本地鏡像文件
$ docker image rm [選項] <鏡像1> [<鏡像2> ...]
可以是鏡像的名字,id都可以。或者指定標籤REPOSITORY:TAG
。
可以組合起來按條件刪除:
$ docker image rm $(docker image ls -q redis)
ls -q
參數表示只顯示只顯示鏡像ID。
- 刪除全部鏡像
docker rmi -f $(docker images -a -q)
容器
docker容器是進程級的,啓動一個容器,也就是啓動了一個進程運行鏡像文件的內容。
- 列出容器
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
575213cf1670 nginx "nginx -g 'daemon of…" 8 days ago Up 4 hours 0.0.0.0:80->80/tcp webserver
這樣只顯示正在運行的容器。
可以加上參數-a
,可以看到已經加載的容器,包括已經運行的和沒運行的。
- 新建並啓動
前面提到,已經拉下來,或者沒有拉下來的鏡像,都可以直接運行。
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
參數太多了,但好像都有用。直接從runoob.com複製過來參數說明:
-a stdin: 指定標準輸入輸出內容類型,可選 STDIN/STDOUT/STDERR 三項;
-d: 後臺運行容器,並返回容器ID;
-i: 以交互模式運行容器,通常與 -t 同時使用;
-P: 隨機端口映射,容器內部端口隨機映射到主機的高端口
-p: 指定端口映射,格式爲:主機(宿主)端口:容器端口
-t: 爲容器重新分配一個僞輸入終端,通常與 -i 同時使用;
--name="nginx-lb": 爲容器指定一個名稱;
--dns 8.8.8.8: 指定容器使用的DNS服務器,默認和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默認和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 設置環境變量;
--env-file=[]: 從指定文件讀入環境變量;
--cpuset="0-2" or --cpuset="0,1,2": 綁定容器到指定CPU運行;
-m :設置容器使用內存最大值;
--net="bridge": 指定容器的網絡連接類型,支持 bridge/host/none/container: 四種類型;
--link=[]: 添加鏈接到另一個容器;
--expose=[]: 開放一個端口或一組端口;
--volume , -v: 綁定一個卷
參數不對,一般是啓動不了的。
比如我剛剛pull
了一個叫httpd
的鏡像下來,執行:
$ docker run -d -p 8080:80 --name apache httpd
把容器的80端口映射到宿主機的8080端口,並且起了個名字叫apache
,在後臺運行。
需要注意的是,再次運行run
則會再次創建一個容器,如果名字相同就會創建失敗。如果端口相同,我這裏是原來啓動的容器被停止,新的容器啓動了。
如果用create
命令,則是隻創建,但不運行容器了。
- 啓動/停止/重啓容器
$ docker start [OPTIONS] CONTAINER [CONTAINER...]
$ docker stop [OPTIONS] CONTAINER [CONTAINER...]
$ docker restart [OPTIONS] CONTAINER [CONTAINER...]
start
和restart
有兩個參數:
-a 將當前的輸入/輸出連接到容器
-i 將當前的輸入連接到容器上
好像輸出都到了宿主機的控制檯了。
已經創建好的容器,可以用這三個命令來控制啓停。
- 執行容器命令
容器啓動之後需要控制容器,執行裏面的命令,或者進入容器的交互終端,可以使用exec
命令:
$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
參數有:
-d :分離模式: 在後臺運行
-i :即使沒有附加也保持STDIN 打開
-t :分配一個僞終端
i
和t
參數往往一起使用。表示打開一個交互終端,比如要進入容器控制檯(類似登錄到linux服務器的樣子)
$ docker exec -it apache bash
就可以執行容器裏面的命令,比如ls
等。
run
命令也可以加入-it
參數,但一般作爲後臺服務來跑,用exec
來控制可能更加多用吧。
除了bash
命令,可以執行容器裏面的其他命令。
- 查看容器的日誌
後臺運行的容器,如果要查看日誌:
$ docker logs [OPTIONS] CONTAINER
參數說明:
-f : 跟蹤日誌輸出
--since :顯示某個開始時間的所有日誌
-t : 顯示時間戳
--tail :僅列出最新N條容器日誌
- 查看容器進程
- 類似linux的top命令一樣
$ docker top CONTAINER
- 刪除容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]
可以是容器的id,或者名字。參數:
-f :通過SIGKILL信號強制刪除一個運行中的容器
-l :移除容器間的網絡連接,而非容器本身
-v :-v 刪除與容器關聯的卷
- 刪除全部容器
docker rm -vf $(docker ps -a -q)
數據卷
前面提到鏡像文件應該是不可變的。一個正式的服務運行起來,會產生很多動態數據,比如數據庫記錄,日誌等,這些信息是很重要的。容器可能可以隨便就刪掉,輕鬆創建,但這些數據不能丟。所以提供了數據卷的概念。在宿主機創建一個卷
,用來保存這些重要的業務數據,就算容器刪除了,卷的數據也不會消失。
- 創建一個卷
$ docker volume create my-vol
在本地的/var/lib/docker/volumes
下面創建my-vol/_data
目錄,作爲卷的實際保存地方。不過有幾個問題:
- 這個
/var/lib/docker/volumes
默認目錄,不知道怎麼改,如果一定要在這裏的話,需要在linux宿主機上專門掛這個目錄才行。 create
命令對於不同的存儲介質有很多參數,docker支持很多存儲介質,比如本地磁盤,nfs設置S3,不同的介質需要對應不同的參數,按照docker的說法,這些參數直接傳給設備,具體就需要去查了。用--driver
指定驅動程序和用-o
指定參數。- mac沒這個目錄!
在linux下沒問題,就有這個目錄,直接把需要的內容弄進去就好了。
但跑到mac電腦的/var/lib
下面根本沒有docker
目錄!docker其實不是直接運行在mac os上,而是在mac os上弄了一個虛擬的linux環境,所以這個/var/lib/docker
目錄對應的是linux虛擬環境的目錄。
執行如下命令進入到linux虛擬環境中:
$ cd ~/Library/Containers/com.docker.docker/Data/vms/0/
$ screen tty
這樣出來的終端界面就能找到對應的目錄了。進去看看,裏面是空的。不知道怎樣把mac的內容拷貝進去。
另外,根據文章指出,這個linux虛擬環境退出,需要按住ctrl然後,按a和k。說其他退出方式,會導致有問題。如果有問題,重啓docker。
mac目錄問題,從[工具][docker]記錄Volume相關引用過來。
比如我要創建了一個叫apache的httpd容器。我打算把真是的網站放在web卷中。先創造卷:
$ docker volume create web
如果是linux就直接把網站內容拷貝到var/lib/docker/volumes/web/_data
裏面,如果是mac就抓瞎。
然後給容器掛載卷。
- 掛載卷
$ docker run -d -p 8080:80 --name apache -v webapp:/usr/local/apache2/htdocs httpd
-v
參數確定卷名:容器中的的絕對路徑
。可以先用exec
進去看看容器裏面對應的網站根目錄在哪裏。如果是linux,拷貝內容進去就好了。如果是mac,換一種方式,直接指定本機目錄掛到容器裏面:
$ docker run -d -p 8080:80 --name apache -v /Users/web:/usr/local/apache2/htdocs httpd
把網站內容拷貝到/Users/web
目錄中就可以。
從 Docker小圖標 -> Preferences 進到 File Sharing。可以看到Users
目錄是共享的。
- 刪除卷
卷不會被自動刪除,需要手工執行:
$ docker volume rm my-vol
進行刪除。
- 查看卷
$ docker volume ls
檢查對象信息
使用inspect
命令檢查對象,比如鏡像,容器,卷的信息。
$ docker inspect 對象名字
可以可以到信息。
幾個常用鏡像包的使用
- mysql
$ docker run -d -e MYSQL_ROOT_PASSWORD=password -p 53306:3306 --privileged=true --name mysql docker.io/mysql
--privileged=true
表示root
在容器內有真正的root
權限。
啓動鏡像, 第一次啓動最少需要指定MYSQL_ROOT_PASSWORD
需要修改使用自己的配置文件,可以通過綁定卷實現。
需要登錄到容器中修改權限。
- nginx
$ docker run --name nginx-test -p 8080:80 -d nginx
需要配置:
-
映射80端口到需要的端口。
-
/etc/nginx/conf
目錄或者/etc/nginx/conf/nginx.conf
,nginx配置文件 -
/usr/share/nginx/html
默認的web根目錄 -
redis
$ docker run -itd --name redis-test -p 6379:6379 redis
可以看出下載一個現成的docker鏡像要用起來的話,有幾個條件需要知道:
- 此鏡像需要暴露那些端口,一般標準的比如web服務器,80端口,redis 6379,java中間件如tomcat 8080端口;mysql 3306端口等。一般官方的都會提供默認端口。
- 瞭解這個鏡像會創建那些卷,雖然創建過程是自動的,但應該知道運行這個鏡像會留下那些東西;
- 那些配置文件是應該放在外面,或者那些目錄應該放在外面的。比如,nginx使用默認的配置文件,那麼就應該把自己的網站文件的目錄映射到
/usr/share/nginx/html
官方提供的鏡像一般都有詳細的說明,hub.docker.com
上也會提供Dockerfile,這個都可以先看的。剩下的,就是多嘗試了,大不了先把鏡像跑起來,用exec
進去看看是怎麼配置的。
製作鏡像文件
從上面的過程來看,docker進行文件的製作纔是最重要的。開發好一個服務端應用之後,怎麼製作鏡像文件,怎麼利用docker合理的部署,需要幾個鏡像,怎麼劃分等。
製作鏡像文件最重要就是編寫Dockerfile。
Dockerfile 分爲四個部分:
- 基礎鏡像(父鏡像)信息指令 FROM。
- 維護者信息指令 MAINTAINER。
- 鏡像操作指令 RUN 、EVN 、ADD 和 WORKDIR 等。
- 容器啓動指令 CMD 、ENTRYPOINT 和 USER 等。
一個最簡單的Dockerfile:
#nginx基礎鏡像
FROM nginx
#指定工作路徑
WORKDIR /usr/share/nginx/html
#將前前路徑下的所有文件都COPY到工作路徑下
COPY . .
#EXPOSE 命令用來指定對外開放的端口,實際用處不大,可不寫
EXPOSE 80
Dcokerfile命令如下:
- FROM
FROM 是用於指定基礎的 images ,一般格式爲 FROM 。所有的 Dockerfile 都應該以 FROM 開頭,FROM 命令指明 Dockerfile 所創建的鏡像文件以什麼鏡像爲基礎,FROM 以後的所有指令都會在 FROM 的基礎上進行創建鏡像。可以在同一個 Dockerfile 中多次使用 FROM 命令用於創建多個鏡像。 - MAINTAINER
MAINTAINER 是用於指定鏡像創建者和聯繫方式,一般格式爲MAINTAINER xxxxx
。 - COPY
COPY 是用於複製本地主機的(爲 Dockerfile 所在目錄的相對路徑)到容器中的。當使用本地目錄爲源目錄時,推薦使用 COPY 。一般格式爲 COPY。例如我們要拷貝當前目錄到容器中的 /app 目錄下,我們可以這樣操作:COPY . /app
- ADD
增強版的COPY,支持將遠程URL的資源加入到鏡像的文件系統。 - ENV
指定鏡像的環境變量。比如常用的path
,JAVA_HOME
等。 - VOLUME
定義卷。格式爲VOLUME ["<路徑1>", "<路徑2>"...]
。 - WORKDIR
WORKDIR 用於配合 RUN,CMD,ENTRYPOINT 命令設置當前工作路徑。可以設置多次,如果是相對路徑,則相對前一個 WORKDIR 命令。默認路徑爲/。一般格式爲WORKDIR /path/to/work/dir
。 - RUN
RUN 用於容器內部執行命令。每個 RUN 命令相當於在原有的鏡像基礎上添加了一個改動層,原有的鏡像不會有變化。一般格式爲 RUN。例如我們要安裝 Python 依賴包,我們做法如下:RUN pip install -r requirements.txt
- EXPOSE
EXPOSE 命令用來指定對外開放的端口。一般格式爲 EXPOSE[…]。例如上面那個例子,開放80端口:EXPOSE 80
- ENTRYPOINT
ENTRYPOINT 可以讓你的容器表現得像一個可執行程序一樣。一個 Dockerfile 中只能有一個 ENTRYPOINT,如果有多個,則最後一個生效。
ENTRYPOINT 命令也有兩種格式:ENTRYPOINT ["executable", "param1", "param2"]
:推薦使用的 Exec 形式。ENTRYPOINT command param1 param2
:Shell 形式。
- CMD
CMD 命令用於啓動容器時默認執行的命令,CMD 命令可以包含可執行文件,也可以不包含可執行文件。
不包含可執行文件的情況下就要用 ENTRYPOINT 指定一個,然後 CMD 命令的參數就會作爲 ENTRYPOINT 的參數。
CMD 命令有三種格式:CMD ["executable","param1","param2"]
:推薦使用的 exec 形式。CMD ["param1","param2"]
:作爲ENTRYPOINT的參數。CMD command param1 param2
:Shell 形式。
一個 Dockerfile 中只能有一個 CMD,如果有多個,則最後一個生效。而 CMD 的 Shell 形式默認調用 /bin/sh -c 執行命令。
CMD 命令會被 Docker 命令行傳入的參數覆蓋:docker run nginx
感謝Docker系列之四:Dockerfile的使用。從這裏參考不少資料。
重點解釋幾個命令:
-
RUN
RUN
命令其實就是構建這個鏡像的時候,基於基礎的鏡像操作系統執行的一些列命令,讓這個環境變成你所要的。比如,基於centos
系統,安裝java安裝數據庫等。一般默認的操作系統是debain
,使用apt-get
安裝軟件,如果選擇centos
則使用yum
來安裝了。
爲了打包快,基本上,第一個乾的事情,是更改apt
或者yum
的源了。
按照說明,一個RUN
命令,形成一個新的鏡像,多個RUN
就是一層一層的做鏡像。如果不想多層鏡像,就把所有的指令都在一個RUN
裏面執行完。命令間用\分割。如:apt update -y \ && apt upgrade \ && apt install mysql-server -y \ && apt install redis-server -y
-
ADD和COPY
兩個命令都是把外部的資源複製到鏡像中。ADD除了支持把主機的文件,還支持遠程URL
資源。但ADD不支持認證。一般也不支持用ADD
獲取遠程資源,可以在RUN
中用wget
獲取。
前面提到更新apt-get
的資源,可以:$ ADD ./sources.list /etc/apt/
sources.list
文件內容:deb http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib deb http://mirrors.ustc.edu.cn/debian/ stretch- updates main non-free contrib deb http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib deb-src http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib deb-src http://mirrors.ustc.edu.cn/debian/ stretch-updates main non-free contrib deb-src http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib deb http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib deb-src http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib
-
ENV環境變量
能在構建容器的時候指定的環境變量就在Dockerfile裏面指定,畢竟,有些環境變量可能在RUN
的時候就會用到。有些比如前面mysql
的鏡像,root
的口令,可以run
的時候指定。 -
ENTRYPOINT和CMD
這兩個指令,在構建鏡像的時候不會運行,在run
的時候執行。相當於鏡像啓動起來的服務。比如,做一個tomcat
的鏡像,啓動容器的時候自動把tomcat
運行起來。
這兩個必須有一個。
兩個命令後面都有帶[]
和不帶中括號的。是所謂的exec
模式(帶中括號)和shell
模式(不帶中括號)。推薦是exec
模式。區別好像很重要,貌似哪個是1號進程。但我不是很清楚。
CMD作爲默認命令,可以被run
的參數覆蓋。
對於 CMD 和 ENTRYPOINT 的設計而言,多數情況下它們應該是單獨使用的。當然,有一個例外是 CMD 爲 ENTRYPOINT 提供默認的可選參數。- 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令會被忽略。
- 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的內容被追加爲 ENTRYPOINT 指定命令的參數。
- 如果 ENTRYPOINT 使用了 exec 模式,CMD 也應該使用 exec 模式。
說了一大堆,其實,一般情況,就用
ENTRYPOINT
好了。別搞這麼複雜。另外,不管CMD
還是ENTRYPOINT
都只能一個生效,如果寫了多個,最後一個生效。如果需要啓動多個服務,就寫一個腳本,COPY
進來,執行就好。
然而,需要注意的是,啓動腳本里面,直接運行命令,而不要用systemctl
這樣啓動服務。如果多個服務,前面的都加&
放到後臺,最後一個放前臺。否則,容器啓動完了就退出了。
比如我的一個啓動腳本:#!/bin/bash mysqld_safe & redis-server & sleep 5s catalina.sh run
我的tomcat如果在mysql沒啓動完成就起來了會出錯,所以讓他睡覺5秒鐘。
-
VOLUME
Dcokerfile裏面定義了卷,在運行的時候,如果不顯示的指定卷,就會自動創建匿名的卷
如果自己做鏡像,可能最麻煩的就是RUN
的環節了。可能需要執行很多命令比如:
- 構建一些目錄
- 設置操作系統的時區,語言
- 安裝各種軟件
- 複製或者ln一些命令
- 如果安裝了數據庫可能需要把數據啓動起來設置密碼和權限再停下來
最好在一個相同的容器裏面,每行命令都執行一下,驗證通過,同步記錄執行的腳本。
最後,構建鏡像的命令,在Dcokerfile目錄下執行:
$ docker build -t runoob/ubuntu:v1
導出鏡像和容器
- 對鏡像文件的操作
導出鏡像文件,文件爲tar
文件。
$ docker save [鏡像名] > [文件名]
導入鏡像文件
$ docker load < [文件名]
鏡像文件是靜態的,不會因爲你在對應的容器裏面做了什麼而改變。一開始製作或者下載的鏡像文件是什麼樣,導出的時候還是什麼樣。
- 對容器快照的操作
容器快照就是運行起來的容器,做了很多操作之後,把當前的快照弄出來變成一個快照文件,這個文件可以恢復成容器。快照文件也是tar
文件。
$ docker export [容器id] > [文件名]
$ docker import [文件名]
可以把導入的鏡像打標籤:
docker tag [鏡像id] [鏡像名字]:[版本號]
不過,要注意的是,導出來的鏡像或者容器快照,都會很大很大。
docker 網絡
docker安裝好之後,主機會多一個docker0
的網卡。用來跟容器通信的。複雜的機制我們不管他,總之,安裝之後就有了。而且,運行容器之後,容器本身也會分配一個ip地址。但這個地址,每次重啓容器,都可能會改變。想用這個地址來做容器之間通信,是不靠譜的。
所以,就需要專門創建網絡。並且把容器都加入到這個網絡裏面,就可以通過容器的名字來通信了。
創建網絡:
$ docker network create congnet
查看這個網絡的信息:
$ docker network inspect congnet
可以看出:
"Scope": "local",
"Driver": "bridge",
"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"
docker網絡有好幾種模式,反正橋接模式就是能訪問所有的網絡。
創建容器,並加入指定網絡:
$ docker run -itd -p 80:80 --name mynginx --net congnet nginx
把已經存在的容器加入到網絡:
$ docker network connect congnet [容器id]
這樣,容器之間就可以互相用容器的名字通信了。
斷開網絡:
$ docker network disconnect congnet mynginx
到這裏,容器都是在一個主機上的。實際情況,很有可能容器在不同的主機上。這就需要單獨的東西。我還沒驗證。根據資料,用overlay
。需要安裝consul
。
暫時不搞他。
docker-compose
下載安裝docker-compose
$ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
即可完成。
docker-compose
使用YAML
文件定義多個鏡像以及依賴關係。
太複雜了,直接複製一個過來。
#版本號
version: "2.1"
#指定創建的虛擬網絡數量
#作用:通過不同的虛擬網絡實現了容器網絡之間的隔離,從而在最大程度上去保護後端網絡的安全。
#networks:
#mynet:
#driver: bridge
#mynet1:
#重用的代碼模板
#模板的定義必須以 x- 開頭
x-logging:
#以 & 開頭的字符串爲模板命名
#以 * 加上模板的名稱引用模板
&default-logging
driver: json-file
options:
max-size: "200k"
max-file: "10"
#定義全局掛載卷
volumes:
test_1.thinking.com:
test_2.thinking.com:
#服務
services:
#服務名稱
todo:
# 構建鏡像
build:
# 指定dockerfile的上下文路徑(相對當前docker-compose.yml的位置)
#包含Dockerfile文件的目錄路徑,或者是git倉庫的URL。
#當提供的值是相對路徑時,它被解釋爲相對於當前compose文件的位置。
#該目錄也是發送到Docker守護程序構建鏡像的上下文。
context: .
#Dockerfile的文件名稱
dockerfile: Dockerfile-todo
args:
# 變量
buildno: 1
password: secret
#Dockerfile裏面可使用的參數變量
#Dockerfile:
# ARG buildno
# ARG password
# RUN echo "Build number: $buildno"
# RUN script-requiring-password.sh "$password"
#鏡像名 : 倉庫/標籤:版本
image: zhanyang/todo-demo:1.0.0
#依賴(以指定順序啓動)
depends_on:
mysql:
condition: service_healthy
#指定一個自定義容器名稱,而不是生成的默認名稱。
#由於Docker容器名稱必須是唯一的,因此如果指定了自定義名稱,則無法將服務擴展到多個容器。
container_name: todo
#卷掛載路徑設置。
#可以設置宿主機路徑 (HOST:CONTAINER) 或加上訪問模式 (HOST:CONTAINER:ro)
#掛載數據卷的默認權限是讀寫(rw),可以通過ro指定爲只讀。
volumes:
# 只需指定一個路徑,讓引擎創建一個卷
- /var/lib/mysql
#指定絕對路徑映射
- /opt/data:/var/lib/mysql
#相對於當前compose文件的相對路徑
- ./cache:/tmp/cache
#用戶家目錄相對路徑
- ~/configs:/etc/configs/:ro
#命名卷
- datavolume:/var/lib/mysql
#使用全局掛載卷
- test_1.thinking.com:/test:rw
#指定日誌驅動爲 json-file,存儲日誌的最大文件 size 爲 200k,最多存儲 10 這樣大的文件。
#logging支持很多driver,而每一個driver對應的options都不一樣
#docker inspect -f {{.HostConfig.LogConfig}} lnmp-nginx
#result:{json-file map[max-file:10 max-size:2000k]}
#docker info |grep 'Logging Driver'
#result:Logging Driver: json-file
#其他:https://docs.docker.com/engine/admin/logging/overview/
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
#指定使用的虛擬網絡
networks:
#- mynet
#覆蓋容器啓動後默認執行的命令。
#該命令也可以是一個類似於dockerfile的列表:command: ["bundle", "exec", "thin", "-p", "3000"]
command: bundle exec thin -p 3000
#may
command: ["/usr/local/nginx/sbin/nginx"]
# 鏈接到另一個服務中的容器。 請指定服務名稱和鏈接別名(SERVICE:ALIAS),或者僅指定服務名稱。
# 實際是通過設置/etc/hosts的域名解析,從而實現容器間的通信。
# 故可以像在應用中使用localhost一樣使用服務的別名鏈接其他容器的服務,前提是多個服務容器在一個網絡中可路由聯通
# links也可以起到和depends_on相似的功能,即定義服務之間的依賴關係,從而確定服務啓動的順序
links:
- db
- db:database
- redis
#鏈接到docker-compose.yml 外部的容器,甚至並非 Compose 管理的容器。參數格式跟 links 類似。
external
- redis_1
- project_db_1:mysql
- project_db_1:postgresql
#暴露端口,但不映射到宿主機,只被連接的服務訪問。 僅可以指定內部端口爲參數
expose:
- "3000"
- "8000"
#暴露端口信息。使用宿主:容器 (HOST:CONTAINER)格式或者僅僅指定容器的端口(宿主將會隨機選擇端口)都可以。
ports:
- "3000"
- "3000-3005"
- "8000:8000"
- "9090-9091:8080-8081"
- "49100:22"
- "127.0.0.1:8001:8001"
- "127.0.0.1:5000-5010:5000-5010"
- "6060:6060/udp"
#v3.2中ports的長格式的語法允許配置不能用短格式表示的附加字段。
ports:
- target: 80 #容器內的端口
published: 8080 #物理主機的端口
protocol: tcp #端口協議(tcp或udp)
mode: host #host 和ingress 兩總模式,host用於在每個節點上發佈主機端口,ingress 用於被負載平衡的swarm模式端口。
#no是默認的重啓策略,在任何情況下都不會重啓容器。
restart: "no"
#指定爲always時,容器總是重新啓動。
restart: always
#如果退出代碼指示出現故障錯誤,則on-failure將重新啓動容器。
restart: on-failure
restart: unless-stopped
#pid 將PID模式設置爲主機PID模式。
#這就打開了容器與主機操作系統之間的共享PID地址空間。
#使用此標誌啓動的容器將能夠訪問和操作裸機的命名空間中的其他容器,反之亦然。
#即打開該選項的容器可以相互通過進程 ID 來訪問和操作。
pid: "host"
#配置 DNS 服務器。可以是一個值,也可以是一個列表。
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
#自定義搜索域
dns_search: example.com
dns_search:
- dc1.example.com
- dc2.example.com
#覆蓋Dockerfile中的entrypoint,用法同Dockerfile中的用法
entrypoint: ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
#添加環境變量。 你可以使用數組或字典兩種形式。
#任何布爾值; true,false,yes,no需要用引號括起來,以確保它們不被YML解析器轉換爲True或False。
environment:
RACK_ENV: development
SHOW: 'true'
SESSION_SECRET:
#【注意】:如果你的服務指定了build選項,那麼在構建過程中通過environment定義的環境變量將不會起作用。
#將使用build的args子選項來定義構建時的環境變量。
environment:
- RACK_ENV=development
- SHOW=true
- SESSION_SECRE
#1>將定義的變量編寫在文件中,然後在yml文件中進行添加
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
#2>例如:
#old:
db:
image: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: redhat
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
#new:
db:
image: mysql
ports:
- "3306:3306"
env_file: ./mysql_env
#創建env_file文件在當前目錄mysql_env
MYSQL_ROOT_PASSWORD=redhat
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=wordpress3
#添加hostname映射,類似於docker cli下面的--add-host
extra_hosts:
- "www.hcstart.com:192.168.101.14"
#配置一個檢查去測試服務中的容器是否運行正常
#具體: https://docs.docker.com/engine/reference/builder/#healthcheck
#查看healthcheck的狀態輸出 : docker inspect lnmp-nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
#labels:添加元數據到container中,查看現有容器的labels:
#docker inspect -f {{.Config.Labels}} lnmp-nginx # lnmp-nginx :容器名
labels:
com.example.description: "Accounting webapp"
com.example.department: "Finance"
com.example.label-with-empty-value: ""
labels:
- "com.example.description=Accounting webapp"
- "com.example.department=Finance"
- "com.example.label-with-empty-value"
#在容器中設置內核參數
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
mysql:
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: tododb
MYSQL_USER: user
MYSQL_PASSWORD: pass
build:
context: .
dockerfile: Dockerfile-mysql
image: zhanyang/mysql:5.6
container_name: mysql
#以 * 加上模板的名稱引用模板 使用全局自定義模板
logging: *default-logging
#指定使用的虛擬網絡
networks:
#- mynet1
參考:docker-compose.yml參數詳解(配置文件)。
在 docker-compose.yml
文件目錄下執行:
$ docker-compose up -d