什么是Docker
Docker 是一個開源的應用容器引擎搁进,讓開發(fā)者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發(fā)布到任何流行的Linux機器上,也可以實現(xiàn)虛擬化,容器是完全使用沙箱機制,相互之間不會有任何接口妻怎。
Docker和虛擬機最大的區(qū)別就是, Docker引擎是基于本地硬件的, Docker在本地硬件的基礎上運行一個Docker引擎, 然后基于該引擎創(chuàng)建相互隔離的環(huán)境, 在每個環(huán)境中運行各自的軟件, 互不影響, 如下圖所示。
Docker的組成
簡單來說,Docker是由鏡像, 倉庫, 容器組成
我們從倉庫(repository)下載鏡像(image), 然后通創(chuàng)建基于該鏡像的容器(container), 之后在容器中運行程序赞弥。
Docker鏡像的存儲方式
Docker鏡像是-分層存儲的, 我們安裝不同的軟件就相當于在鏡像中添加一層, 比如我們安裝一個linux, 這image就增加一層linux, 我們安裝一個apache tomcat, 鏡像中就新添加一層tomcat, 我們不但可以添加層, 還可以控制每層的元素。
Docker容器
Docker容器就相當于基于docker鏡像創(chuàng)建的環(huán)境中的一個進程, 每個容器之間是隔離的, 互相不影響, 只要我們使用的是同一個鏡像, 那么創(chuàng)建出來的容器的環(huán)境就是相同的, 這樣就保證了我們環(huán)境的統(tǒng)一性。
當我們創(chuàng)建一個容器, 就相當于在鏡像的最上面又增加了一個可讀可寫的層, 由于鏡像是只讀的, 所以我們對容器進行任何操作都不會影響到鏡像, 這就是Docker可以保證環(huán)境的統(tǒng)一性的原因嫁艇。
Docker倉庫
Docker倉庫就是存儲和管理鏡像的一個遠程服務器, 我們可以像倉庫中上傳我們自己的鏡像, 也可以下載別人創(chuàng)建好的鏡像。
Docker安裝
window和mac請直接在官網(wǎng)下載Docker客戶端, 下面我們用ubuntu為例, 來說明Docker的安裝
ubuntu
apt-get update
apt-get install -y docker.io
或者使用下列命令從docker.com獲取最新版本的安裝包自動安裝
curl -s https://get.docker.com | sh
安裝完成后使用下面命令查看版本
docker version
如果能看到版本說明安裝成功, 之后用下面的命令啟動docker服務
service docker start
第一個Docker容器
執(zhí)行下面命令從Docker官網(wǎng)獲取一個指定的鏡像
docker pull [options] name[:tags]
這里我們獲取一個叫hello-world的鏡像
docker pull hello-world
使用下列命令查看本機鏡像
docker images [options] [repository[:tag]]
這里我們查看本機所有image
docker images
或docker image ls
我們會看到以下內(nèi)容
$ docker image ls
REPOSITORY TAG IMAGE ID
hello-world latest 326387cea398
- 使用下列命令創(chuàng)建一個容器
docker run [options] imageName[:tag] [command] [args]
這里我們只創(chuàng)建一個基于hello-world鏡像的容器, 不做任何操作
docker run hello-world
通過上面的三步, 我們就創(chuàng)建了一個Docker容器
刪除容器
docker container rm -r containerId
刪除鏡像
docker rm imageId
實踐: 運行一個Nginx容器
運行Nginx容器時, 我們主要有以下三點要求:
- 持久化運行容器
- 后臺運行
- 進入容器內(nèi)執(zhí)行操作
從倉庫下載Nginx鏡像
docker pull nginx
運行Nginx容器, -d參數(shù)可以運行并返回容器的id, 用這種方式啟動的容器是后臺啟動的, 通過這種方式運行的容器, 會開一個持續(xù)運行的進程
docker run -d -p 9999:80 nginx
查看正在運行的容器
docker ps
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
1fa4ab2cf395 nginx "ngix -g deamon of ..." 28 seconds ago Up 2 minutes 0.0.0.0:9999->80/tcp
我們可以看到正在運行的容器的id, 端口映射, 運行狀態(tài)等信息
我們可以用下面的方法停止一個運行的容器
docker container containerId stop
或docker stop containerId
同樣我們也可以打開指定的容器
docker container containerId start
或docker start containerId
下面的命令可以查看本機所有容器, 包括正在運行的和沒有運行的
docker container ls -a
- 進入正在運行的指定容器中
docker exec -it containerId command
比如我們要使用bash進入當前正在運行的那個id為f1fa4ab2cf395的容器中, 這里id只輸入前幾位就行了
docker exec -it 1fa4ab bash
通過上面這些命令, 我們就可以操作一個真實的nginx容器, 并將容器的80端口映射到我們電腦的4000端口上, 這樣我們就可以通過本機的9999端口訪問容器的80端口了
- 我們訪問本地的localhost:9999就會打開一個nginx頁面, 這就說明我們的容器創(chuàng)建并運行成功了
Docker容器的網(wǎng)絡
由于Docker的隔離性, 因此默認情況下Docker的網(wǎng)絡也是被隔離的, 我們需要對Docker的網(wǎng)絡進行一些配置, 才可以實現(xiàn)網(wǎng)絡通信
Docker網(wǎng)絡類型
- Bridge 橋接模式
默認模式, 也叫映射模式, 在橋接模式下, 容器擁有自己的網(wǎng)卡和ip及端口號, 容器通過虛擬的網(wǎng)橋和主機的網(wǎng)卡進行映射, 從而實現(xiàn)和外界通信, 默認情況下, 由于我們沒有設置映射關系, 所以docker不知道容器應該通過哪個端口來和主機映射, 所以默認情況下是沒有辦法訪問docker的網(wǎng)絡的 - Host 主機模式
docker容器和主機共用網(wǎng)絡, 容器內(nèi)看到的網(wǎng)卡就是主機的網(wǎng)卡 - None 隔離模式
不能訪問網(wǎng)絡
我們可以通過以下命令創(chuàng)建并后臺啟動一個配置映射的容器
docker run -d -p hostIp:containerIp imageName
創(chuàng)建后我們可以在本機上輸入下列命令看主機的對應端口是否被監(jiān)聽, 如果已經(jīng)被監(jiān)聽, 就說明我們創(chuàng)建映成功了
netstat -na | grep hostIp
通過上面的步驟我們就創(chuàng)建了一個可以網(wǎng)絡通信的Docker容器
Docker鏡像的創(chuàng)建
Docker鏡像的創(chuàng)建基于Dockerfile這個文件, 我們通過在該文件中配置, 然后就可以創(chuàng)建我們自己的容器了, 這里我們按照Docker官網(wǎng)的事例來一步一步創(chuàng)建自己的容器
- 創(chuàng)建一個目錄, 進入該目錄中, 在該目錄中創(chuàng)建一個Dockerfile文件
Dockerfile
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
- 根據(jù)上面的文件描述, 我們需要一個requirements.txt來定義python安裝的依賴, 還需要一個app.py文件保存我們的代碼, 因此我們需要創(chuàng)建這兩個文件
requirements.txt
Flask
Redis
app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>" \
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
這時我們的文件夾中應該有以下三個文件
$ ls
Dockerfile app.py requirements.txt
- 在本地創(chuàng)建Docker鏡像, 并用--tag命令為該鏡像命名和標簽
docker build --tag=friendlyhello .
創(chuàng)建后我們就會看到類似下面的文件, 這樣就說明我們本地創(chuàng)建鏡像成功了,
$ docker image ls
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
- 之后我們就可以按照之前我們學過的命令創(chuàng)建容器和端口映射, 運行容器了
docker run -d -p 4000:80 friendlyhello
-
用瀏覽器訪問localhost:4000, 如果看到下面的頁面, 就說明我們?nèi)萜鲃?chuàng)建成功了