cgroups 进程级的虚拟化技术出现的比较晚,所以 Docker 2013年才诞生。

image.png

1. 为什么需要 Docker

  • 保证开发、测试、交付、部署的环境完全一致
  • 保证资源的隔离
  • 启动临时的、用完即弃的环境,例如测试
  • 迅速(秒级)超大规模部署和扩容

2. Docker 基本使用

  • 镜像 image【一个预先定义好的模板文件,Docker 引擎可以据此启动无数个一模一样,互不干扰的容器】
  • 容器 container【一台虚拟计算机,拥有独立的网络、文件系统、进程,默认和宿主机无任何交互】

docker pull/images

  • 下载指定镜像,方便随时启动
  • docker pull mysql:8:0:18 下载指定镜像
  • docker images 查看本地已有镜像

image.png

docker run/ps

  • docker run 装载镜像成为一个容器,每个容器有一个 ID,引用 ID 时支持缩写。
  • docker run -it <镜像名> <镜像中要运行的命令和参数> ,交互式命令行,当前 shell 中运行,Ctrl+C退出。
  • -it(等价于 -i -t)参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。
  • docker run -d <镜像名> <镜像中要运行的命令和参数> , daemon 模式,在后台运行。
  • -d 模式下 ,镜像中要运行的命令一般由镜像来定义。
  • —rm 可以在镜像退出时自动删除容器。
  • 在镜像名之前,全都是 docker 本身的参数,顺序随意,而在镜像名之后,是要传递给容器的参数。
  • docker ps 列出当前运行的容器(-a 会包括已经停止的容器)

下面例子中,明明是交互模式,为什么退出了?
因为 ubuntu 的 dockerfile(后面会提到这是什么,先理解为是装机清单)写了 CMD ["bash"] 因此执行 bash 命令,而这里却显式地传入了 echo 命令,而 echo 命令本身是执行完就退出,所以下面的表现就是打印 balabala 后就立即 exit:

  1. docker run -it ubuntu echo "balabala"

docker run 和宿主机产生交互

  • —name 为容器指定一个名字
  • —restart=always 遇到错误自动重启
  • -v <本地文件>:<容器文件>
  • -p <本地端口>:<容器端口>
  • -e NAME=VALUE 环境变量

  • -v 文件映射

把宿主机的文件映射到容器中,使得双方对该文件的更改都生效:

  1. $ docker run -it -v `pwd`/output.txt:/root/test.txt ubuntu
  • -p 端口映射

比如启动一个 mysql:

  1. $ docker run --name some-mysql -v ~/Projects/data/mysql:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql

有了端口映射,就可以同一台机器上分布式部署,只要映射不同端口号即可。

  • -e 环境变量

刚才启动 mysql 时就传入了环境变量,会被 mysql 用来作为 root 密码。
再来启动个 Ubuntu,然后进去打印传入的环境变量:

  1. $ docker run -it -e NAME=VALUE ubuntu

image.png

docker start/stop

  • 启动/停止一个容器,可以理解为开关机

docker rm/rmi

  • 删除一个容器/镜像,可以理解为扔掉电脑

docker exec

  • docker exec 在一个正在运行的容器中执行一个命令,可以粗略地想象成 SSH
  • docker run -it <正在运行的目标容器ID> <目标命令(通常为 bash)>

可以用来排查错误排查等:

  1. docker exec -it some-mysql bash

docker logs

  • docker logs <容器 ID 或容器名> 查看目标容器的输出
  • docker logs -f <容器 ID 或容器名> -f 可以暂不退出命令,用来跟进实时的输出
    1. docker logs -f <容器ID>

    docker inspect

    高级命令,用于查看容器的详细状态,先知道有这么回事,用到时再深究。

3. Dockerfile 与镜像仓库

Dockerfile 文件

  • 指定镜像如何生成
  • 每个镜像会有一个唯一 ID
  • 使用 docker build 进行镜像构建

创建一个 Dockerfile 文件,内容如下:

  1. FROM ubuntu:16.04
  2. RUN apt-get update && apt-get install -y nginx && nginx
  3. EXPOSE 80

然后构建镜像(这里可以先不起名字):

  1. # 先进入到刚才 Dockerfile 目录,然后执行:
  2. # . 代表当前文件夹路径,该路径是此次的构建上下文,其中包含了 Dockerfile 文件,以及镜像中需要用到的资源,
  3. # 可以从构建上下文中拷贝到镜像中(本例的 Dockerfile 中不包括拷贝命令)
  4. $ docker build .
  5. # -t 参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是 latest
  6. $ docker image build -t nginx-demo:0.0.1 .

等待镜像构建完成,看一下镜像列表,发现刚创建的镜像没有仓库和 tag 信息:

$ docker images

image.png
刚才说了可以构建镜像的时候指定,也可以构建之后再添加:

$ docker tag <镜像ID> <镜像仓库+镜像名>:<版本信息>
# 如果省略标签,则默认是 latest
$ docker tag <镜像ID> <镜像仓库+镜像名>
$ docker run -it -p 8080:80 <镜像ID>

新开个终端, docker ps 可以看到已经运行的容器。
然后浏览器中访问:
image.png

搭建 Docker 私有镜像仓库

除了中央仓库和第三方仓库外,也可以自行搭建镜像仓库,使用如下命令(具体参见底部官方文档链接):

docker run -d -p 5000:5000 --restart always --name registry registry:2 # 显然对其这个仓库服务,其本身也是个镜像

还记得刚才怎么添加仓库和标签信息吗?现在有了私有仓库后,打个像模像样的标签信息:

$ docker tag 18fb5496761d 127.0.0.1:5000/nginx-demo:0.0.1

image.png
然后 push 刚才的镜像:

docker push 127.0.0.1:5000/nginx-demo:0.0.1

image.png
访问本地镜像仓库提供的 API,获得 nginx-demo 镜像的 tag 列表:
http://localhost:5000/v2/nginx-demo/tags/list
image.png
也可以 pull,但因为本地已经有了该镜像,所以会提示已经是最新(可以删了镜像 再 pull 试试):

docker pull 127.0.0.1:5000/nginx-demo:0.0.1
  • —registry-mirror 可以为 docker 客户端指定镜像地址,在客户端的设置中添加
  • —insecure-registry 仓库没有 HTTPS 的话,添加该标记以通过 HTTP 来访问

4. 参考

  1. Docker 入门教程-阮一峰
  2. https://docs.docker.com/registry/
  3. Dockerfile 中的 COPY 与 ADD 命令-博客园(sparkdev)