前端工程師學(xué)Docker?看這篇就夠了
傳統(tǒng)的虛擬機(jī),非常耗費(fèi)性能
Docker可以看成一個(gè)高性能的虛擬機(jī),并且不會(huì)浪費(fèi)資源,主要用于Linux環(huán)境的虛擬化,類(lèi)似VBox這種虛擬機(jī),不同的是Docker專(zhuān)門(mén)為了服務(wù)器虛擬化,并支持鏡像分享等功能。前端工程師也可以用于構(gòu)建代碼等等。
目前看,Dokcer不僅帶火了GO語(yǔ)言,還會(huì)持續(xù)火下去。
首先,我們看看傳統(tǒng)的虛擬機(jī)和Docker的區(qū)別。
傳統(tǒng)的虛擬機(jī):
Docker:
可以看到,傳統(tǒng)的虛擬機(jī)是每開(kāi)一個(gè)虛擬機(jī),相當(dāng)于運(yùn)行一個(gè)系統(tǒng),這種是非常占用系統(tǒng)資源的,但是Docker就不會(huì)。但是也做到了隔離的效果
Docker容器虛擬化的優(yōu)點(diǎn):
- 環(huán)境隔離
Docker實(shí)現(xiàn)了資源隔離,實(shí)現(xiàn)一臺(tái)機(jī)器運(yùn)行多個(gè)容器互不影響。
2. 更快速的交付部署
使用Docker,開(kāi)發(fā)人員可以利用鏡像快速構(gòu)建一套標(biāo)準(zhǔn)的研發(fā)環(huán)境,開(kāi)發(fā)完成后,測(cè)試和運(yùn)維人員可以直接通過(guò)使用相同的環(huán)境來(lái)部署代碼。
3. 更高效的資源利用
Docker容器的運(yùn)行不需要額外的虛擬化管理程序的支持,它是內(nèi)核級(jí)的虛擬化,可以實(shí)現(xiàn)更高的性能,同時(shí)對(duì)資源的額外需求很低。
4. 更易遷移擴(kuò)展
Docker容器幾乎可以在任意的平臺(tái)上運(yùn)行,包括烏力吉、虛擬機(jī)、公有云、私有云、個(gè)人電腦、服務(wù)器等,這種兼容性讓用戶(hù)可以在不同平臺(tái)之間輕松的遷移應(yīng)用。
5. 更簡(jiǎn)單的更新管理
使用Dockerfile,只需要小小的配置修改,就可以替代以往的大量的更新工作。并且所有修改都是以增量的方式進(jìn)行分發(fā)和更新,從而實(shí)現(xiàn)自動(dòng)化和高效的容器管理。
正式開(kāi)始
本文撰寫(xiě)于2019年10月13日
電腦系統(tǒng):Mac OS
使用最新版官網(wǎng)下載的Docker
以下代碼均手寫(xiě),可運(yùn)行
下載官網(wǎng)的Docker安裝包,然后直接安裝
Docker官網(wǎng)下載地址
安裝后直接打開(kāi)
打開(kāi)終端命令行,輸入docker,會(huì)出現(xiàn)以下信息,那么說(shuō)明安裝成功。
下載安裝成功后,首先學(xué)習(xí)下Docker的兩個(gè)核心知識(shí)點(diǎn)
container(容器)和image(鏡像)
Docker的整個(gè)生命周期由三部分組成:鏡像(image)+容器(container)+倉(cāng)庫(kù)(repository)
思維導(dǎo)圖如下:
該如何理解呢?
每臺(tái)宿主機(jī)(電腦),他下載好了Docker后,可以生成多個(gè)鏡像,每個(gè)鏡像,可以創(chuàng)建多個(gè)容器。發(fā)布到倉(cāng)庫(kù)時(shí),以鏡像為單位??梢岳斫獬桑阂粋€(gè)容器就是一個(gè)獨(dú)立的虛擬操作系統(tǒng),互不影響,而鏡像就是這個(gè)操作系統(tǒng)的安裝包。想要生成一個(gè)容器,就用安裝包(鏡像)生成一次
上面就是Docker的核心概念,下面開(kāi)始正式操作
補(bǔ)充一點(diǎn):如果想深入Docker , 還是要去認(rèn)真學(xué)習(xí)下原理,今天我們主要講應(yīng)用層面的
首先,我們回到終端命令行操作
輸入:
- docker images
如果你的電腦上之前有創(chuàng)建過(guò)的鏡像,會(huì)得到如下:
如果沒(méi)有的話(huà)就是空~
我們首先創(chuàng)建一個(gè)自己的鏡像
先編寫(xiě)一個(gè)Node.js服務(wù)
創(chuàng)建index.js
- // index.js
- const Koa = require('koa');
- const app = new Koa();
- app.use(async ctx => {
- ctx.body = 'Hello docker';
- });
- app.listen(3000);
然后配置package.json文件
- {
- "name": "app",
- "version": "1.0.0",
- "private": true,
- "scripts": {
- "start": "node server.js"
- },
- "dependencies": {
- "koa": "^2.5.0"
- }
- }
正常情況下 使用
npm start 或 node index.js 就可以啟動(dòng)服務(wù)
可是我們這里需要打包進(jìn)Docker中,這里就需要寫(xiě)一個(gè)配置文件dockerfile
vsCode有天然插件支持
在目錄下新建文件dockerfile,加入如下配置
- FROM node
- ADD . /app/
- EXPOSE 3000
- WORKDIR /app
- RUN npm install
- CMD ["node","./index.js"]
解釋一下,上面這些配置的作用
FROM 是設(shè)置基礎(chǔ)鏡像,我們這里需要Node
ADD是將當(dāng)前文件夾下的哪些文件添加到鏡像中 參數(shù)是 [src,target]
這里我們使用的 . 意思是所有文件,當(dāng)然跟git一樣,可以配置ignore文件
EXPOSE是向外暴露的端口號(hào)
WORKDIR是說(shuō)工作目錄,我們這里將文件添加到的是app目錄,所以配置app目錄為工作目錄,
這樣就不用在命令行前面加/app了
RUN是先要執(zhí)行的腳本命令
CMD是執(zhí)行的cmd命令
可以想一想,我們打包好鏡像后,然后啟動(dòng)鏡像會(huì)發(fā)生什么?
文件編寫(xiě)完,使用命令打包鏡像
使用命令打包已經(jīng)好的文件目錄
- docker image build ./ -t app
打包后出現(xiàn)提示:
此時(shí)我們查看Docker鏡像,使用命令:
- docker images
我們可以清楚看到,app鏡像已經(jīng)打包成功,下面我們啟動(dòng)它
- docker run -p 8000:3000 app
使用上面命令即可啟動(dòng)我們的鏡像,這時(shí)我們?cè)诿钪休斎?nbsp;
- curl 127.0.0.1:8000
得到返回內(nèi)容
Hello docker
瀏覽器輸入: 127.0.0.1:8000 即可訪問(wèn)到頁(yè)面~
以上說(shuō)明,我們的第一個(gè)Docker鏡像已經(jīng)制作成功
有人可能會(huì)覺(jué)得到這里,鏡像和容器有點(diǎn)混淆了,不是先有鏡像再有容器嗎?
其實(shí)是我們啟動(dòng)的鏡像有腳本命令幫我們啟動(dòng)了服務(wù),于是Docker幫我們自動(dòng)創(chuàng)建了容器
查看Docker容器命令:
- docker ps -a 列出所有容器
- 不加 -a 僅列出正在運(yùn)行的,像退出了的或者僅僅只是創(chuàng)建了的就不列出來(lái)
- docker container ls 列出當(dāng)前運(yùn)行的容器
輸入上面 docker container ls
得到結(jié)果
原來(lái)Docker看我們啟動(dòng)了腳本服務(wù),幫我們自動(dòng)生成了容器?
下面我們來(lái)一個(gè)生成鏡像,再生成容器,最后手動(dòng)啟動(dòng)容器的例子
這次我們配置,加入Nginx反向代理服務(wù)器
首先,創(chuàng)建用戶(hù)需要看到的html文件
這里我們給一個(gè)普通的 hello-world內(nèi)容的index.html文件即可
然后創(chuàng)建dickerfile文件,配置如下,將index.html文件添加到對(duì)應(yīng)的位置
- FROM nginx
- COPY ./index.html /usr/share/nginx/html/index.html
- EXPOSE 80
對(duì)外暴露端口號(hào)80
這里特別提示:配置文件怎么寫(xiě),根據(jù)你的基礎(chǔ)鏡像來(lái),百度基本都能找到,不用糾結(jié)這個(gè)
此時(shí)的文件結(jié)構(gòu):
老規(guī)矩,開(kāi)始打包
- docker build ./ -t html
打印信息:
輸入終端命令:
- docker images
得到結(jié)果:
新的鏡像html已經(jīng)構(gòu)建成功,但是此時(shí)查看容器,是沒(méi)有正在運(yùn)行的
輸入命令:
docker container ls //查看正在運(yùn)行的所有容器
docker container ls -a //查看所有容器
得到結(jié)果是:
可以確認(rèn)的是,我們創(chuàng)建鏡像不會(huì)自動(dòng)生成和啟動(dòng)容器
我們手動(dòng)生成容器
- docker container create -p 8000:80 html
此時(shí)命令行返回 一段值
輸入
- docker container ls
沒(méi)有顯示有任何啟動(dòng)的容器,這時(shí)候我們手動(dòng)啟動(dòng)
輸入
- docker container start ***(上面那段值)
再重復(fù) docker container ls 命令
得到結(jié)果
此時(shí)訪問(wèn)localhost:8000即可正常訪問(wèn)頁(yè)面~
至此,我們可以確定,創(chuàng)建鏡像只要不啟動(dòng),不會(huì)生成容器,更不會(huì)運(yùn)行容器
那怎樣將Docker用在前端的日常構(gòu)建中呢?
我們使用gitHub+travis+docker來(lái)形成一套完整的自動(dòng)化流水線
只要我們push新的代碼到gitHub上,自動(dòng)幫我們構(gòu)建出新的代碼,然后我們拉取新的鏡像即可(gitLab也有對(duì)應(yīng)的代碼更新事件鉤子,可以參考那位手動(dòng)實(shí)現(xiàn)Jenkens的文章)
首先我們先進(jìn)入 Travis CI 官網(wǎng)配置,注冊(cè)綁定自己的gitHub賬號(hào)
然后在左側(cè)將自己需要git push后自動(dòng)構(gòu)建鏡像的倉(cāng)庫(kù)加入
接著在項(xiàng)目根目錄配置 .travis.yml 文件
- language: node_js
- node_js:
- - '12'
- services:
- - docker
- before_install:
- - npm install
- - npm install -g parcel-bundler
- script:
- - parcel build ./index.js
- - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- - docker build -t jinjietan/mini-react:latest .
- - docker push jinjietan/mini-react:latest
每次更新push代碼,都會(huì)下載,然后執(zhí)行打包命令,這樣你下載的鏡像就是有最新的代碼。不再需要每個(gè)人下載打開(kāi)鏡像再去build
為了降低復(fù)雜度,這里使用了Parcel打包工具,零配置
更改dockerfile內(nèi)容,將parcel打包后的內(nèi)容COPY進(jìn)容器
- FROM nginx
- COPY ./index.html /usr/share/nginx/html/
- COPY ./dist /usr/share/nginx/html/dist
- EXPOSE 80
添加好了你的庫(kù)之后,選擇這里的設(shè)置
然后添加兩個(gè)環(huán)境變量:
DOCKER_USERNAME和DOCKER_PASSWORD
這里,我將我編寫(xiě)的mini-react框架源碼,放入docker中,然后使用parcel打包工具打包,再用nginx反向代理~
特別提示:這里的Docker容器,想要后臺(tái)運(yùn)行,就必須有一個(gè)前臺(tái)進(jìn)程。容器運(yùn)行的命令如果不是那些一直掛起的命令(比如tcp,ping),就是會(huì)自動(dòng)退出的
通過(guò) docker ps -a 可以看到容器關(guān)閉的原因
注意 :jinejietan/mini-react應(yīng)該換成你的用戶(hù)名/包名,再push代碼
這是思維導(dǎo)圖:
當(dāng)配置成功,代碼被推送到gitHub上后,travis-ci幫我們自動(dòng)構(gòu)建發(fā)布新鏡像
一定要學(xué)會(huì)使用: docker ps -a 查看容器的狀態(tài)
成功的提示:
至此,發(fā)布,自動(dòng)構(gòu)建鏡像已經(jīng)完成
正式開(kāi)始拉取鏡像,啟動(dòng)容器
我們剛才發(fā)布的鏡像名稱(chēng)是:jinjietan/mini-react
先使用下面幾條命令
- docker中 啟動(dòng)所有的容器命令
- docker start $(docker ps -a | awk '{ print $1}' | tail -n +2)
- docker中 關(guān)閉所有的容器命令
- docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
- docker中 刪除所有的容器命令
- docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2)
- docker中 刪除所有的鏡像
- docker rmi $(docker images | awk '{print $3}' |tail -n +2)
- tail -n +2 表示從第二行開(kāi)始讀取
清除當(dāng)前宿主機(jī)上面所有的鏡像,容器,依次執(zhí)行
然后使用:
- docker image pull jinjietan/mini-react:latest
拉取鏡像,這時(shí)候需要下載
拉取完成后,使用
- docker images
可以看到j(luò)injietan/mini-react:latest鏡像已經(jīng)存在了
我們使用
- docker container create -p 8000:80 jinjietan/mini-react:latest
創(chuàng)建這個(gè)鏡像的容器,并且綁定在端口號(hào)8000上
最后輸入下面的命令,即可啟動(dòng)mini-react框架的容器
- docker container start ***(上面create的返回值)
瀏覽器輸入 127.0.0.1:8000 發(fā)現(xiàn),訪問(wèn)成功,框架生效。
Docker的使用,我們大致就到這里,個(gè)人認(rèn)為,用Docker比不用好,這個(gè)技術(shù)已經(jīng)快跟TypeScript一樣,到不學(xué)不行的階段了。
并不是說(shuō)你非要用它,而是比如說(shuō),你如果不怎么懂TypeScript,你就沒(méi)辦法把如今那些優(yōu)秀庫(kù)的大部門(mén)的源碼搞得那么清楚。
越來(lái)越多的技術(shù)在依賴(lài)Docker
當(dāng)然,其實(shí)這個(gè)mini-react框架源碼也是不錯(cuò)的,如果有興趣可以了解以下,源碼都在:
mini-react框架+鏡像配置源碼,記得切換到diff-async分支哦~