本文內容仍是相對很淺的,Docker中關於分佈式,集羣的內容沒有涉及,因此本文推薦前端同窗看一看,後端同窗就不推薦了。本文中全部命令都是針對Ubuntu16.04,拷貝粘貼時請注意。(這一篇文章有些復讀機🎺,對docker感興趣的能夠直接看如下的參考資料)html
本文主要參考瞭如下資料前端
命令彙總,方面快速查詢node
# 建立鏡像
docker build -t [鏡像名] .
# Docker鏡像列表
docker image ls
# 刪除鏡像
docker rmi [id]
# 刪除全部的鏡像
docker image rm $(docker image ls -a -q)
# Docker容器列表
docker container ls
docker container ls --all
# 所有的中止的容器
docker container ls -aq
# 刪除容器
docker rm [id]
# 刪除全部的容器
docker container rm $(docker container ls -a -q)
# 中止容器
docker container stop [id]
# 啓動中止的容器
docker container start [id]
# 強制關閉指定容器
docker container kill [id]
# 重啓容器
docker container restart [id]
# 進入容器內部
docker exec -it [容器id] bash
# 運行容器,外部的4000端口映射到容器的80端口
docker run -p 4000:80 hello
# 指定容器的名稱 --name
docker run --name [name] -p 4000:80 [image]
# 守護態運行容器(後臺運行,不須要在打開一個終端)
docker run -d -p 4000:80 hello
# 隨機映射本機的端口到容器的端口
docker run -d -P [image]
# 映射全部的地址
docker run -d -p [宿主機端口]:[容器端口] [image]
# 映射指定地址以及端口
docker run -d -p [ip]:[宿主機端口]:[容器端口] [image]
# 映射指定地址的任意端口
docker run -d -p [ip]::[容器端口] [image]
# 查看容器映射的端口
docker port [容器名|容器id] [容器的端口]
# 標記鏡像
docker tag [鏡像名] [用戶名]/[存儲庫]:[標籤]
# 上傳鏡像到DockerHub
docker push [用戶名]/[存儲庫]:[標籤]
# 從DockeerHub上獲取鏡像
docker pull [存儲庫]:[標籤]
# 從存儲庫運行鏡像
docker run -p [用戶名]/[存儲庫]:[標籤]
# 建立數據卷
docker volume create [數據卷名稱]
# 查看全部的數據卷
docker volume ls
# 查看數據卷的信息
docker volume inspect [數據卷名稱]
# 刪除數據卷
docker volume rm [數據卷名稱]
# 清理無主的數據卷
docker volume prune
# 查看網絡列表
docker network ls
複製代碼
Docker的虛擬化是在系統層面實現的,虛擬機則是在硬件方面實現的。linux
Docker Images 是一個可執行的包。包含了運行應用程序的全部內容,代碼,運行時,環境變量,庫,配置文件。nginx
鏡像的構建是一層層構建的,前一層是後一層的基礎。每一層構建完成後,不會再改變。後面的修改的只會發生當前的鏡像層。好比刪除前一層的文件,並非真正的刪除。而是在後面的鏡像層中標記爲刪除,刪除的文件會一直存在鏡像中。git
分層的特性使得鏡像容易擴展和複用。好比在Docker Hub上提供的各類基礎鏡像。github
咱們在上面說過鏡像是分層的。咱們這裏利用commit命令深刻理解下鏡像的構成。web
咱們使用docker run --name webserver -d -p 4880:80 nginx構建nginx的容器。使用exec進入webserver容器,並進行了必定的修改。而docker commit命令能夠將咱們對容器存儲層的修改保存下來,成爲新的鏡像。新的鏡像由原有的鏡像,加上咱們更改的存儲層構成的。redis
Docker Containers 是鏡像運行的實例。可使用docker ps查看正在運行的容器列表。容器一樣也是多層存儲,以鏡像做爲基礎層,在基礎層上加一層容器運行的存儲層。mongodb
sudo apt-get remove docker docker-engine docker.io containerd runc
複製代碼
# 更新apt
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# 添加官方GPG密鑰
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 將存儲庫添加到APT源
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 更新apt
sudo apt-get update
# 安裝
sudo apt-get install docker-ce docker-ce-cli containerd.io
複製代碼
# 查看docker版本
docker version
複製代碼
# 容許hello-world鏡像,驗證是否正確安裝
docker run hello-world
複製代碼
在過去若是要編寫Python應用程序,須要在機器上安裝Python運行時,不只僅須要在你的開發機器配置環境,並且還須要在生產環境的機器上配置環境。若是使用Docker,能夠把Python運行時經過鏡像獲取,無需在不一樣的機器上重複安裝環境。能夠在應用程序,和Python運行時鏡像打包在一塊兒。確保在不一樣的機器上均可以正常運行。這些可移植的鏡像,由Dockerfile定義
Dockerfile定義了容器內的環境。容器與系統的其餘部分相隔離,所以須要將容器的端口映射到外部。由這個Dockerfile定義的應用程序的構建,運行在任何地方的行爲都徹底相同。
# 建立空文件夾,並在文件夾中建立Dockerfile文件
mkdir learn-docker
cd learn-docker
touch Dockerfile
touch app.js
複製代碼
# 在Dockerfile寫入如下的內容
vim Dockerfile
# 將node做爲父鏡像
FROM node
# 將容器的工做目錄設置爲/app(當前目錄,若是/app不存在,WORKDIR會建立/app文件夾)
WORKDIR /app
# 將當前文件夾中的全部內容,複製到容器的/app中
COPY . /app
# 安裝node包
RUN npm install
# 容器對外暴露80端口
EXPOSE 80
# 環境變量
ENV NAME World
# 容器啓動時運行app.js
CMD ["node", "app.js"]
複製代碼
const express = require('express')
const app = express()
app.get('/', function (req, res) {
res.send('hello world')
})
app.listen(80, '0.0.0.0')
複製代碼
咱們並不須要在系統中安裝Python,Flask或者Redis。構建運行鏡像的時候也不須要安裝它們。雖然看起來咱們沒有使用Pyhone構建開發環境,可是咱們已經這樣作了。
使用docker build命令,構建鏡像。(--tag選項會對鏡像進行命名)
# 構建hellodocker的鏡像
docker build --tag=hellodocker .
# 構建完成後,咱們查看鏡像列表
docker image ls
複製代碼
# 將服務器的4000端口映射到容器的80端口
docker run -p 3999:80 hellodocker
# 查看正在運行的容器
docker container ls
# curl測試,返回helloworld
curl 0.0.0.0:3999
複製代碼
FROM指令用於指定鏡像的基礎鏡像。FROM scratch,能夠指定空的基礎鏡像。
Dockerfile中每個指令都會創建一層鏡像,不該該把RUN指令看成shell腳原本寫。
FROM scratch
# 這回額外的建立7層鏡像,這是錯誤的行爲
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
# 正確的寫法應當是,使用&&將命令串連,簡化爲一層鏡像
RUN buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
# 清除無用的緩存,避免Docker的臃腫
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
複製代碼
COPY指令將當前目錄的文件,複製到image中。
源路徑指的是當前上下文的目錄。目標路徑能夠是容器內的絕對路徑路徑,也能夠是容器WORKDIR指定的工做目錄的相對路徑。
COPY [源路徑] [目標路徑]
複製代碼
CMD指定容器主進程的啓動命令。
# 使用node
CMD ["node", "app.js"]
# 使用pm2
# http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/#docker-integration
RUN npm install pm2 -g
CMD ["pm2-runtime", "app.js"]
複製代碼
VOLUME指令能夠指定某個目錄爲匿名卷,任何對該目錄的寫操做,不會記錄到容器的存儲層。
對於數據庫,數據庫文件應保存到數據卷中
VOLUME /data
複製代碼
ENV指令用來設置環境變量,Dockerfile後面的指令或者代碼中,均可以使用該環境變量
# Dockerfile
# 環境變量
ENV NAME World
複製代碼
// app.js
const express = require('express')
const app = express()
app.get('/', function (req, res) {
// 使用環境變量
res.send(`hello world${process.env.NAME}`)
})
app.listen(80, '0.0.0.0')
複製代碼
EXPOSE指令用於聲明端口,可是EXPOSE聲明的端口要和docker run <宿主端口>:<容器端口>區分。EXPOSE指令僅僅是聲明,而不會自動進行端口映射。
WORKDIR用來指定當前目錄(工做目錄),Dockerfile不是shell腳本,這一點須要切記。
# 這是錯誤的示範
RUN cd /app
RUN echo "hello" > world.txt
複製代碼
這裏並不會建立 /app/world.txt的文件。由於在Dockerfile中兩行RUN的執行環境是不一樣的。因此第一層的 cd /app 不會影響到第二層的當前目錄,正確的作法應當是。
WORKDIR /app
RUN echo "hello" > world.txt
複製代碼
DockerHub相似於Github,由Docker官方維護的一個公共容器鏡像倉庫。咱們首先註冊,並登陸Docker Hub
# 登陸
docker login
# 標記鏡像
# docker tag [鏡像名] [用戶名]/[存儲庫]:[標籤]
docker tag hellodocker zhangyue9467/learn-docker:test
複製代碼
docker push zhangyue9467/learn-docker:test
複製代碼
Docker Hub倉庫中就會有咱們發佈的鏡像
使用Docker後,咱們不須要在其餘機器上安裝任何東西,就能夠運行它。只須要遠程拉取Docker的鏡像
docker run -p 3998:80 zhangyue9467/learn-docker:test
複製代碼
數據卷是一個可供一個或多個容器使用的特殊目錄, 數據卷中的數據能夠容器之間共享和重用。對數據卷的修改會立馬生效。
# 建立一個名爲vol的數據卷
docker volume create vol
# 查看數據卷中的信息
docker volume inspect vol
複製代碼
Mountpoint中是數據卷掛載在宿主機的位置。咱們在Mountpoint字段對應的文件夾內建立一個文件
使用--mount,在啓動容器時掛載數據卷,容器啓動時能夠掛載多個數據卷。
# 啓動了name爲web的容器
# 使用vol數據卷,加載到容器的/webapp中
docker run -d -P \
--name web \
--mount source=vol,target=/webapp \
hello
複製代碼
進入web容器進行查看,vol數據卷中內容掛載到容器的/webapp目錄中
宿主機的路徑必須是絕對路徑,使用--mount若是主機目錄不存在Docker會報錯。Docker默認對主機目錄的權限是讀寫權限。
# 啓動了name爲web2的容器
# 使用本機/var/www/vol目錄做爲數據卷,加載到容器的/webapp中
docker run -d -P \
--name web2 \
--mount type=bind,source=/var/www/vol,target=/webapp \
hello
複製代碼
# /root/.bash_history 做爲卷
docker run -d -P \
--name web3 \
--mount type=bind,source=/root/.bash_history,target=/root/.bash_history \
hello
複製代碼
在容器內部能夠獲取外部的命令行的歷史記錄
# 映射任意端口到容器的端口
docker run -d -P [image]
# 映射全部的地址
# docker run -d -p 5000:5000 web
docker run -d -p [宿主機端口]:[容器端口] [image]
# 映射指定地址以及端口
# docker run -d -p 127.0.0.1:5000:5000 web
docker run -d -p [ip]:[宿主機端口]:[容器端口] [image]
# 映射指定地址的任意端口
# docker run -d -p 127.0.0.1::5000 web
docker run -d -p [ip]::[容器端口] [image]
複製代碼
# 查看容器映射的端口
docker port [容器名|容器id] [容器的端口]
複製代碼
容器內部擁有自身的網絡和ip,可使用docker inspect命令在"NetworkSettings"中獲取。
# 查看容器內部的ip信息
docker inspect [容器id]
複製代碼
使用自定義Docker網絡實現容器通訊。若是是多個容器可使用Docker Compose實現容器間的通信,Docker Compose默認全部容器都在同一個網絡中的。
# 建立網絡
docker network create -d bridge mynet
# 將容器連接到網絡mynet中
docker run -d -p 5000:8888 --name busybox1 --network mynet hello
docker run -d -p 5001:8889 --name busybox2 --network mynet hello2
# 進入容器busybox1內部,可使用curl或者ping,測試
# busybox2的ip地址
curl 172.19.0.3:8889
#
ping busybox2
複製代碼
使用Dockerfile文件能夠很方便定義一個容器。但在平常的工做中一個項目可能須要多個容器(前端,後端,數據庫)。Compose容許用戶定義docker-compose.yml模版文件,來定義一組相關聯的容器爲一組項目。
Compose中兩個概念:
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
複製代碼
驗證docker composc的安裝
# 查看版本
docker-compose --version
複製代碼
更多命令請參考。
💡在介紹Compose命令以前,我以爲有必要明確一下,服務與容器的概念。我曾經混淆過它們的概念,詳細的解答請參考
在docker-compose中,docker-compose.ymal中定義的是服務, 下面定義了一個名爲web的服務。而web的服務會啓動一個名爲"[項目文件的名稱]_web"的容器。
# docker-compose.ymal
version: '3'
services:
web:
build: .
ports:
- "5000:3000"
複製代碼
在項目的目錄根目錄下運行build命令,構建鏡像
# 構建容器
docker-compose build
複製代碼
在項目的根目錄下運行ps命令,列出項目中的全部容器
docker-compose ps
複製代碼
up命令將會完成構建容器,建立服務,啓動服務,等一系列操做。能夠直接經過up命令啓動一個項目
# 在前臺啓動容器
docker-compose up
# 在後臺啓動並運行項目(不須要強制退出控制檯了)
docker-compose up -d
複製代碼
查看服務映射在宿主機上的端口
version: '3'
services:
web:
build: .
ports:
- "5000:3000"
複製代碼
# 示例
# 0.0.0.0:5000
docker-compose port web[服務] 3000[容器端口]
複製代碼
更多指令請參考
version: '3'
services:
# web服務
web:
# 容器的名稱
container_name: hello_compose
# Dockerfile文件的位置(絕對路徑,相對docker-compose模版文件的路徑均可以)
build: .
# 暴露端口,但不映射到宿主機
expose:
- "3000"
# 暴露端口 [宿主端口]:[容器端口]
ports:
- "5000:3000"
# 數據卷掛載的路徑
# https://forums.docker.com/t/making-volumes-with-docker-compose/45657
volumes:
- [宿主機路徑]:[容器路徑]
# db服務
db:
# 容器使用的鏡像
image: "redis:alpine"
複製代碼
新建jenkins任務,將github上的項目拉取到線上雲服務器的空文件夾中。
接着定義Dockerfile自定義鏡像。使用FROM指令將nginx做爲父鏡像,使用COPY指令將上下文目錄的全部內容拷貝到容器的/var/www/hello_docker/目錄中。/var/www/hello_docker/是咱們在nginx配置中配置的靜態文件目錄。接着使用COPY指令將nginx的配置文件,拷貝到/etc/nginx/conf.d/目錄中。conf.d文件夾內的nginx配置文件的內容,會合併到nginx主配置文件中。緊接着使用RUN指令重啓nginx服務。
使用Dockerfile自定義咱們的鏡像後,須要經過build命令構建咱們的鏡像。因爲須要作到運維的自動化,直接啓動咱們的鏡像可能會產生錯誤(可能存在同名的鏡像)。咱們使用shell腳本判斷是否須要刪除以前的鏡像仍是直接啓動容器。最後使用run命令構建咱們的容器。
# Dockerfile
FROM nginx
COPY ./* /var/www/hello_docker/
COPY ./nginx/hello_docker.conf /etc/nginx/conf.d/
RUN service nginx restart
複製代碼
# nginx.conf
server {
listen 8888;
server_name localhost;
root /var/www/hello_docker;
index index.html;
expires 7d;
}
複製代碼
容器構建完成後,咱們在本地沒法直接訪問容器映射的接口,咱們須要在☁️雲服務器配置nginx代理,訪問容器。
(咱們將轉發請求到容器映射的接口上)前端的部署同以前的項目一致(這裏略過)。使用Dockerfile定義後端服務鏡像,使用FROM指令將node做爲父鏡像,使用RUN指令在全局安裝pm2,使用CMD指令, 使用pm2啓動後端的服務。
FROM node
WORKDIR /server
COPY . /server
EXPOSE 8888
RUN npm install pm2 -g
CMD ["pm2-runtime", "app.js"]
複製代碼
咱們直接使用docker-compose部署mongo數據庫。
須要注意的是,mongo數據存儲的位置,不建議直接將數據直接存儲到容器中。而是使用volumes,將容器內數據庫的存儲目錄掛載到宿主機的目錄中
version: '3.1'
services:
mongo:
# 使用docker hub 的mongo鏡像
image: mongo
# 容器重啓策略
restart: always
# 容器啓動的參數
command:
- '--auth'
- '-f'
- '/etc/mongod.conf'
# 指定數據卷,配置文件以及數據存儲的位置
volumes:
- '/etc/mongod.conf:/etc/mongod.conf'
- '/var/lib/mongodb:/var/lib/mongodb'
ports:
- '37017:27017'
複製代碼