通常使用docker run --name XX image:tag
這樣的命令來啟動(dòng)容器后荔泳,會(huì)遇到兩種情況猪叙。
- 容器啟動(dòng)后再標(biāo)準(zhǔn)輸出打印了一些信息,然后就停在那里了。如果我們使用
ctrl-c
或ctrl-d
退出后容器就結(jié)束了叹侄。 - 容器啟動(dòng)后很快就自己結(jié)束了,然后就沒有然后了绝淡。
這兩種都不熟我們期望的結(jié)果昌抠。我們希望容器在啟動(dòng)后持續(xù)運(yùn)行,等待我們的再次臨幸轨功。對(duì)于這個(gè)問題網(wǎng)上有很多文章介紹旭斥,但能夠?qū)⑶宄暮苌佟N疫@里整理了一下希望能夠讓讀者清晰的理解這種現(xiàn)象的原因以及應(yīng)對(duì)方法古涧。
沒有耐心讀長(zhǎng)文的同學(xué)可以直接看最后的總結(jié)
CMD
執(zhí)行命令的三種差別
Docker Image
在制作時(shí)通過Dockerfile
的CMD
命令指定了容器啟動(dòng)后執(zhí)行的程序垂券。這個(gè)指定程序決定了容器是否結(jié)束和如何結(jié)束。
我們來看看三種不同的情況:
1. CMD
指定了一個(gè)持續(xù)運(yùn)行的程序.
持續(xù)運(yùn)行就是說程序不會(huì)主動(dòng)退出羡滑。我們拿postgres
的舉栗子菇爪。
# 先來看一看postgres的CMD程序是哪個(gè)
$ docker pull postgres:11-alpine
...
...
$ docker inspect postgres:11-alpine
...
"Cmd": [
"postgres"
],
...
我們看到容器在啟動(dòng)后會(huì)指定
postgres
程序,這個(gè)程序會(huì)持續(xù)運(yùn)行啄栓。我們運(yùn)行起來看看娄帖。
$ docker run --name pp postgres:11-alpine
...[一堆輸出信息]...
2019-02-03 13:46:46.117 UTC [1] LOG: database system is ready to accept connections
[停在這里不動(dòng)了]
[我們?cè)撛趺崔k?]
ctrl-c
[然后就沒有然后了]
容器成功啟動(dòng)了
postgres
程序,一旦按下ctrl-c
程序終止了昙楚,容器也就退出了近速。
解決辦法
運(yùn)行時(shí)添加
-d
參數(shù)$ docker run --name pp -d postgres:11-alpine 1c1e99ac3fd3f18c6558bfc8b0fd08e4bf7aaad80535dd6ea709892f20f06f27
可以看到添加
-d
參數(shù)后docker run
命令輸出了容器的ID而不是像之前那樣輸出postgres
程序執(zhí)行的內(nèi)容。$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c1e99ac3fd3 postgres:11-alpine "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 5432/tcp pp
通過
docker ps
命令看到容器確實(shí)啟動(dòng)起來堪旧,并持續(xù)運(yùn)行削葱。完美。
我們看看
-d
參數(shù)的解釋$ docker run --help ... -d, --detach Run container in background and print container ID ...
這個(gè)參數(shù)的含義就是對(duì)容器說:"我知道你在努力做事淳梦,但我也很忙析砸,你自己到旁邊干活去吧,有事兒我再找你"
2. CMD
指定了一個(gè)shell
這次我們用node
舉栗子
$ docker pull node:10-alpine
$ docker inspect node:10-alpine
...
"Cmd": [
"node"
],
...
node
程序與postgres
程序不太一樣爆袍。node
并不是我們上面談的"持續(xù)運(yùn)行"的概念首繁。
它作為一種shell
程序自身并不知道要做什么,而是需要與操作者交流從而執(zhí)行操作者交付的任務(wù)陨囊。
而shell
與操作者之間交流的方式是通過tty
進(jìn)行的弦疮。如果tty
沒有了那么shell
發(fā)現(xiàn)沒有人理它了,它就會(huì)在孤獨(dú)和寂寞中睡覺去了蜘醋。
而當(dāng)容器啟動(dòng)的時(shí)候并不會(huì)給程序分配一個(gè)tty
胁塞,所以這就是我們看到啟動(dòng)shell
程序的容器自動(dòng)退出的原因。
解決辦法
運(yùn)行時(shí)添加
-t
參數(shù)$ docker run --name nn -t node:10-alpine > [這是shell提示符]
我們來看看
-t
參數(shù)的解釋$ docker run --help ... -t, --tty Allocate a pseudo-TTY ...
這個(gè)參數(shù)的含義是:"瞧這個(gè)泰迪熊多可愛,你去和它聊天吧"
現(xiàn)在我們看到了
shell 提示符
,現(xiàn)在的狀態(tài)與第一種情況類似了啸罢,下面我們只需要再加入-d
參數(shù)就完美了$ docker run --name nn -dt node:10-alpine bfeead85bf01dd182e4c631ee9077afbb5c989e9c75abdd4776086dd223b9cdc
我們期待的容器ID由出現(xiàn)了编检,完美。
3. CMD
指定了一個(gè)普通程序
這種鏡像不好找扰才,我們用參數(shù)模擬一下允懂。在啟動(dòng)容器是通過命令行參數(shù)指定容器啟動(dòng)的程序,這將替換CMD
指定的程序衩匣。
$ docker run --name nn -dt node:10-alpine pwd
412baf5fc0428567bcce3a2cb00fc41a696c10ecda0447d23a9291c2a2b52f20
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
412baf5fc042 node:10-alpine "pwd" 2 minutes ago Exited (0) 2 minutes ago nn
雖然容器啟動(dòng)時(shí)返回了容器ID累驮,但當(dāng)我們查看容器狀態(tài)時(shí)它已經(jīng)Exited
。
起始這種容器設(shè)計(jì)之初就不是讓它持續(xù)運(yùn)行的舵揭,它只是為了完成一項(xiàng)專門的動(dòng)作,然后去睡覺躁锡。
那么對(duì)于這樣的容器我們改怎么辦呢午绳?
? Let it go, ? let it go
? Can't hold it back anymore
? Let it go, ? let it go
? Turn my back and slam the door
### 總結(jié)
根據(jù)CMD
指定的程序不同,有三種情況需要考慮
- 對(duì)于自身持續(xù)運(yùn)行的程序,指定
-d
參數(shù)映之。它就可以自己到角落里畫圈圈去了拦焚。 - 對(duì)于一個(gè)
shell
程序,指定-dt
參數(shù)杠输。給它一只泰迪熊赎败,它就去角落和和泰迪熊聊天去了。 - 對(duì)于一個(gè)執(zhí)行完就結(jié)束的程序蠢甲。我們只能
Let it go