【学习笔记】Docker - 02. 在容器中运行软件(上)
2.1?控制容器:?構(gòu)建一個(gè)網(wǎng)站監(jiān)視器?
需求:?客戶想讓你做一個(gè)網(wǎng)站,?這個(gè)網(wǎng)站需要被緊密的監(jiān)視,?如果服務(wù)器宕機(jī)了,?那么它們的團(tuán)隊(duì)會(huì)收到相關(guān)的郵件.?
這里用到了3個(gè)容器.?第一個(gè)運(yùn)行NGINX;?第二個(gè)運(yùn)行一個(gè)叫做mailer的程序.?這兩個(gè)容器都是detached的.?
Detached?表示容器將在后臺(tái)運(yùn)行,?不會(huì)附加到任何的輸入或者是輸出流上面.?
第三個(gè)容器,?叫做代理,?將會(huì)運(yùn)行在一個(gè)交戶的容器內(nèi)?
?
2.1.1?創(chuàng)建并開始一個(gè)容器?
Docker把運(yùn)行一個(gè)程序所需要的那些文件和指令叫做鏡像. 當(dāng)我們使用Docker安裝軟件的時(shí)候, 我們實(shí)際上是在使用Docker下載或創(chuàng)建容器. Docker鏡像包含了一臺(tái)電腦要運(yùn)行某個(gè)軟件所需的所有東西.?
?
從Docker Hub下載NGINX鏡像.??
Docker Hub是Docker 公司提供的公共注冊中心, 而NGINX是一個(gè)可信的倉庫.?
?
運(yùn)行下面的命令將會(huì)下載, 安裝, 和開始一個(gè)運(yùn)行著NGINX的容器:?
docker run --detach --name web nginx:latest?
當(dāng)你運(yùn)行這個(gè)命令的時(shí)候, Docker會(huì)從NGINX倉庫安裝nginx:latest這個(gè)版本的鏡像, 而NGINX倉庫則是在Docker Hub上面托管的, 然后會(huì)立即運(yùn)行這個(gè)軟件.?
?
運(yùn)行起來之后, 在終端上將會(huì)出現(xiàn)類似這樣的隨機(jī)字符串:?
7cb5d2b9a7eab87f07182b5bf58936c9947890995b1b94f412912fa822a9ecb5?
這堆字符串是容器的唯一標(biāo)識(shí)符, 每次你使用docker run并創(chuàng)建一個(gè)新容器的時(shí)候, 它都會(huì)得到一個(gè)唯一標(biāo)識(shí)符.?
?
標(biāo)識(shí)符顯示出來之后, 好像什么也沒發(fā)生, 這是因?yàn)槟闶褂?--detach?這個(gè)參數(shù), 它會(huì)讓你的程序在后臺(tái)運(yùn)行. 這就是意味著你的程序已經(jīng)啟動(dòng)了, 但是沒有附加到你的終端上. 像類似NGINX這樣的服務(wù)器軟件通常都不需要附加在終端上的, 所以通常都是運(yùn)行在detached的容器里.?
?
對于那些在后臺(tái)安靜運(yùn)行的程序來說, 運(yùn)行detached的容器是再合適不過的了. 這類程序通常叫做daemon(守護(hù)進(jìn)程)或服務(wù). 守護(hù)進(jìn)程通常會(huì)通過網(wǎng)絡(luò)或其他通信渠道來和其它程序或人類交互. 當(dāng)你想要在容器里的后臺(tái)運(yùn)行daemon或其他程序的時(shí)候, 就需要使用 --detach 這個(gè)flag, 簡寫是?-d.?
?
本例中另一個(gè)daemon是mailer(郵件程序), mailer會(huì)等待調(diào)用者發(fā)起連接, 然后發(fā)送一個(gè)郵件.?
安裝和運(yùn)行mailer的命令:?
docker run -d --name mailer dockerinaction/ch2_mailer?
?
2.1.2?運(yùn)行交互式的容器?
例如, 基于終端的文本編輯器就是需要附加終端的程序. 它通過鍵盤等設(shè)備得到輸入, 并把輸出顯式在終端上. 所以在它的輸入輸出流上, 它是可交互的.?
開始使用交互式的容器:?
docker run --interactive --tty \?
???? --link web:web \?
???? --name web_test \?
???? busybox:1.29 /bin/sh?
針對run命令, 這里用到了兩個(gè)flag:?
--interactive (簡寫是 -i). 這個(gè)選項(xiàng)告訴Docker讓標(biāo)準(zhǔn)輸入流(stdin)為容器保持打開, 即使沒有終端被附加上.?
--tty (-t). 它會(huì)告訴Docker為容器分配一個(gè)虛擬終端, 你就可以通過這個(gè)終端來傳遞指令給容器.?
針對交互式的程序, 這兩個(gè)flag通常一起使用.?
?
和交互式的flags一樣重要, 當(dāng)你啟動(dòng)容器的時(shí)候, 你指定了一個(gè)在容器內(nèi)要運(yùn)行的程序. 本例中就是一個(gè)shell程序叫做sh.?
?
這段命令最終創(chuàng)建了一個(gè)容器, 開啟了一個(gè)UNIX shell, 并且鏈接到了運(yùn)行NGINX的容器. 從shell里, 你可以運(yùn)行一個(gè)命令來驗(yàn)證你的web server是否正常運(yùn)行:?
wget -O -?http://web:80/?
如果得到以下結(jié)果,?那么就是成功了:?
想要關(guān)閉交互式容器的話,?你可以輸入?exit.?這就會(huì)終止shell程序并且停止容器.?
?
也可以創(chuàng)建一個(gè)交互式容器,?手動(dòng)在容器里開始一個(gè)進(jìn)程,?然后detach你的終端.?這就需要按住Ctrl和P鍵,?然后松開P鍵去按Q鍵.?但是只有你使用--tty這個(gè)參數(shù)的時(shí)候,?它才會(huì)起作用.?
?
2.1.3?列出,?停止,?重啟容器以及查看容器的輸出.??
使用docker ps命令來查看正在運(yùn)行等容器.?
運(yùn)行該命令后,?針對每個(gè)運(yùn)行的容器,?將會(huì)顯示以下信息:?
容器的ID?
用了哪個(gè)鏡像?
容器內(nèi)執(zhí)行了的命令?
自從容器建立以來經(jīng)過的時(shí)間?
程序運(yùn)行了多久?
容器暴露的網(wǎng)絡(luò)端口?
容器的名字?
現(xiàn)在,?你應(yīng)該有三個(gè)容器了,?名字分別是web, mailer?和?agent.?
?
重啟容器:?docker restart xxx?
例如:??
docker restart web?
docker restart mailer?
docker restart agent?
?
查看容器的日志:?docker logs xxx?
例如:?
docker logs web?
如果過于依賴docker logs,?那么可能會(huì)有危險(xiǎn).?因?yàn)槿魏纬绦驅(qū)懭氲?/span>stdout或stderr輸出流的東西將會(huì)在這個(gè)log里面被記錄.?這種模式的缺點(diǎn)是log在默認(rèn)情況下不會(huì)循環(huán)或截?cái)?/span>,?所以容器寫入到log的數(shù)據(jù)將會(huì)和容器一起一直保留.?對于長存的進(jìn)程,?這種長期的持久化可能會(huì)是個(gè)問題.?更好處理log數(shù)據(jù)的方式是使用卷(volumes).?
docker logs?命令也有flag參數(shù), --follow或-f,?加上它之后就會(huì)在顯示出當(dāng)前日志的同時(shí)并繼續(xù)監(jiān)視如果有新的日日志,?那么就更新顯示的日志.?當(dāng)你不想看的時(shí)候,?就按Ctrl + C?終端logs命令即可?
?
停止容器中PID為1的程序(停止容器):?docker stop xxx?
例如: docker stop web?
?
2.2?解決問題?與?PID命名空間?
在Linux上每一個(gè)運(yùn)行的程序或者叫進(jìn)程都有一個(gè)唯一的數(shù)字叫做進(jìn)程標(biāo)識(shí)符(PID).?
PID命名空間就是一套唯一的數(shù)字,?它們可以識(shí)別出不同的進(jìn)程.?
Linux提供了可以創(chuàng)建多個(gè)PID命名空間的工具.??
每個(gè)命名空間都有一整套可能的PID.?
這就意味著每個(gè)PID命名空間都會(huì)包含它自己的PID 1,2,3….?
?
大多數(shù)程序都不需要訪問其他正在運(yùn)行的進(jìn)程,?也不需要列出系統(tǒng)中其他正在運(yùn)行的進(jìn)程.??
所以?Docker默認(rèn)會(huì)為每個(gè)容器創(chuàng)建新的PID命名空間.?一個(gè)容器的PID命名空間會(huì)把這個(gè)容器的進(jìn)程與其它容器的進(jìn)程隔離開.?
?
從容器內(nèi)一個(gè)擁有自己命名空間的進(jìn)程的角度來看, PID 1?可能是指初始化系統(tǒng)的進(jìn)程,?例如runit或supervisord.在不同的容器, PID 1也許是指像bash一樣的命令行shell.?
執(zhí)行結(jié)果分別是:?
?
?
在這個(gè)例子里,?你使用了?docker exec?命令在容器里運(yùn)行額外的進(jìn)程.?
這里的ps命令,?它會(huì)顯示出所有運(yùn)行的進(jìn)程和它們的PID.?
?
和大多數(shù)Docker隔離特性一樣,?你可以選擇不使用它們的PID命名空間來創(chuàng)建容器.?如果你正在使用某個(gè)程序來執(zhí)行系統(tǒng)管理任務(wù),?并且這項(xiàng)工作需要從容器內(nèi)列舉出進(jìn)程,?那么這點(diǎn)就很重要.?
你可以在docker create?或?docker run?命令上設(shè)定?--pid flag的值為host,?這樣的話,?就可以實(shí)現(xiàn)以上需求了.?
???
假設(shè)你沒有使用Docker,?而是直接在你的機(jī)器上運(yùn)行NGINX.?假設(shè)你把這件事忘記了,?并且又開啟了一遍NGINX,?那么這第二個(gè)進(jìn)程就無法訪問它需要的資源,?因?yàn)榈谝粋€(gè)進(jìn)程已經(jīng)擁有它們了.?這就是軟件沖突的例子.?你可以試試:?
結(jié)果是:?
第二個(gè)進(jìn)程啟動(dòng)失敗,?并且報(bào)告說它需要的地址已經(jīng)在使用.?這叫做端口沖突.?
?
然而Docker可以簡化并解決這個(gè)問題:?
所以,?環(huán)境獨(dú)立性可以讓依賴于稀缺系統(tǒng)資源的軟件能自由的配置,?而且無需考慮本地其它軟件的沖突需求.?
?
下面是一些常見的沖突問題:?
兩個(gè)程序想綁定同一個(gè)網(wǎng)絡(luò)端口?
兩個(gè)程序使用同樣的臨時(shí)文件名, 而且文件別鎖了以防止發(fā)生這樣的事?
兩個(gè)程序使用不同版本的全局安裝的庫?
兩個(gè)進(jìn)程想使用相同的PID文件?
后安裝的程序修改了另一個(gè)程序使用的環(huán)境變量, 然后第一個(gè)程序崩潰了?
多個(gè)進(jìn)程搶CPU或內(nèi)存資源.?
當(dāng)一個(gè)或多個(gè)程序擁有共同依賴并且無法協(xié)商共享或需求不同的時(shí)候, 這些沖突就會(huì)出現(xiàn).?
?
而Docker通過Linux命名空間,?資源限制,?文件系統(tǒng)root?和?虛擬化網(wǎng)絡(luò)組件等這些工具, 就解決了這些軟件的沖突. 所有的這些工具都是被用來在Docker容器內(nèi)進(jìn)行軟件隔離的.?
總結(jié)
以上是生活随笔為你收集整理的【学习笔记】Docker - 02. 在容器中运行软件(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET Core on K8S深
- 下一篇: 今天,全网曝光这几个公众号