什么是Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
Docker和虚拟机最大的区别就是, Docker引擎是基于本地硬件的, Docker在本地硬件的基础上运行一个Docker引擎, 然后基于该引擎创建相互隔离的环境, 在每个环境中运行各自的软件, 互不影响, 如下图所示。
Docker的组成
简单来说,Docker是由镜像, 仓库, 容器组成
我们从仓库(repository)下载镜像(image), 然后通创建基于该镜像的容器(container), 之后在容器中运行程序。
Docker镜像的存储方式
Docker镜像是-分层存储的, 我们安装不同的软件就相当于在镜像中添加一层, 比如我们安装一个linux, 这image就增加一层linux, 我们安装一个apache tomcat, 镜像中就新添加一层tomcat, 我们不但可以添加层, 还可以控制每层的元素。
Docker容器
Docker容器就相当于基于docker镜像创建的环境中的一个进程, 每个容器之间是隔离的, 互相不影响, 只要我们使用的是同一个镜像, 那么创建出来的容器的环境就是相同的, 这样就保证了我们环境的统一性。
当我们创建一个容器, 就相当于在镜像的最上面又增加了一个可读可写的层, 由于镜像是只读的, 所以我们对容器进行任何操作都不会影响到镜像, 这就是Docker可以保证环境的统一性的原因。
Docker仓库
Docker仓库就是存储和管理镜像的一个远程服务器, 我们可以像仓库中上传我们自己的镜像, 也可以下载别人创建好的镜像。
Docker安装
window和mac请直接在官网下载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容器
执行下面命令从Docker官网获取一个指定的镜像
docker pull [options] name[:tags]
这里我们获取一个叫hello-world的镜像
docker pull hello-world
使用下列命令查看本机镜像
docker images [options] [repository[:tag]]
这里我们查看本机所有image
docker images
或docker image ls
我们会看到以下内容
$ docker image ls
REPOSITORY TAG IMAGE ID
hello-world latest 326387cea398
- 使用下列命令创建一个容器
docker run [options] imageName[:tag] [command] [args]
这里我们只创建一个基于hello-world镜像的容器, 不做任何操作
docker run hello-world
通过上面的三步, 我们就创建了一个Docker容器
删除容器
docker container rm -r containerId
删除镜像
docker rm imageId
实践: 运行一个Nginx容器
运行Nginx容器时, 我们主要有以下三点要求:
- 持久化运行容器
- 后台运行
- 进入容器内执行操作
从仓库下载Nginx镜像
docker pull nginx
运行Nginx容器, -d参数可以运行并返回容器的id, 用这种方式启动的容器是后台启动的, 通过这种方式运行的容器, 会开一个持续运行的进程
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, 端口映射, 运行状态等信息
我们可以用下面的方法停止一个运行的容器
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页面, 这就说明我们的容器创建并运行成功了
Docker容器的网络
由于Docker的隔离性, 因此默认情况下Docker的网络也是被隔离的, 我们需要对Docker的网络进行一些配置, 才可以实现网络通信
Docker网络类型
- Bridge 桥接模式
默认模式, 也叫映射模式, 在桥接模式下, 容器拥有自己的网卡和ip及端口号, 容器通过虚拟的网桥和主机的网卡进行映射, 从而实现和外界通信, 默认情况下, 由于我们没有设置映射关系, 所以docker不知道容器应该通过哪个端口来和主机映射, 所以默认情况下是没有办法访问docker的网络的 - Host 主机模式
docker容器和主机共用网络, 容器内看到的网卡就是主机的网卡 - None 隔离模式
不能访问网络
我们可以通过以下命令创建并后台启动一个配置映射的容器
docker run -d -p hostIp:containerIp imageName
创建后我们可以在本机上输入下列命令看主机的对应端口是否被监听, 如果已经被监听, 就说明我们创建映成功了
netstat -na | grep hostIp
通过上面的步骤我们就创建了一个可以网络通信的Docker容器
Docker镜像的创建
Docker镜像的创建基于Dockerfile这个文件, 我们通过在该文件中配置, 然后就可以创建我们自己的容器了, 这里我们按照Docker官网的事例来一步一步创建自己的容器
- 创建一个目录, 进入该目录中, 在该目录中创建一个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"]
- 根据上面的文件描述, 我们需要一个requirements.txt来定义python安装的依赖, 还需要一个app.py文件保存我们的代码, 因此我们需要创建这两个文件
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
- 在本地创建Docker镜像, 并用--tag命令为该镜像命名和标签
docker build --tag=friendlyhello .
创建后我们就会看到类似下面的文件, 这样就说明我们本地创建镜像成功了,
$ docker image ls
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
- 之后我们就可以按照之前我们学过的命令创建容器和端口映射, 运行容器了
docker run -d -p 4000:80 friendlyhello
-
用浏览器访问localhost:4000, 如果看到下面的页面, 就说明我们容器创建成功了