cgroups 进程级的虚拟化技术出现的比较晚,所以 Docker 2013年才诞生。
1. 为什么需要 Docker
- 保证开发、测试、交付、部署的环境完全一致
- 保证资源的隔离
- 启动临时的、用完即弃的环境,例如测试
- 迅速(秒级)超大规模部署和扩容
2. Docker 基本使用
- 镜像 image【一个预先定义好的模板文件,Docker 引擎可以据此启动无数个一模一样,互不干扰的容器】
- 容器 container【一台虚拟计算机,拥有独立的网络、文件系统、进程,默认和宿主机无任何交互】
docker pull/images
- 下载指定镜像,方便随时启动
- docker pull mysql:8:0:18 下载指定镜像
- docker images 查看本地已有镜像
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:
docker run -it ubuntu echo "balabala"
docker run 和宿主机产生交互
- —name 为容器指定一个名字
- —restart=always 遇到错误自动重启
- -v <本地文件>:<容器文件>
- -p <本地端口>:<容器端口>
-e NAME=VALUE 环境变量
-v 文件映射
把宿主机的文件映射到容器中,使得双方对该文件的更改都生效:
$ docker run -it -v `pwd`/output.txt:/root/test.txt ubuntu
- -p 端口映射
比如启动一个 mysql:
$ 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,然后进去打印传入的环境变量:
$ docker run -it -e NAME=VALUE ubuntu
docker start/stop
- 启动/停止一个容器,可以理解为开关机
docker rm/rmi
- 删除一个容器/镜像,可以理解为扔掉电脑
docker exec
- docker exec 在一个正在运行的容器中执行一个命令,可以粗略地想象成 SSH
docker run -it <正在运行的目标容器ID> <目标命令(通常为 bash)>
可以用来排查错误排查等:
docker exec -it some-mysql bash
docker logs
docker logs <容器 ID 或容器名>
查看目标容器的输出docker logs -f <容器 ID 或容器名>
-f
可以暂不退出命令,用来跟进实时的输出docker logs -f <容器ID>
docker inspect
高级命令,用于查看容器的详细状态,先知道有这么回事,用到时再深究。
3. Dockerfile 与镜像仓库
Dockerfile 文件
- 指定镜像如何生成
- 每个镜像会有一个唯一 ID
- 使用 docker build 进行镜像构建
创建一个 Dockerfile 文件,内容如下:
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y nginx && nginx
EXPOSE 80
然后构建镜像(这里可以先不起名字):
# 先进入到刚才 Dockerfile 目录,然后执行:
# . 代表当前文件夹路径,该路径是此次的构建上下文,其中包含了 Dockerfile 文件,以及镜像中需要用到的资源,
# 可以从构建上下文中拷贝到镜像中(本例的 Dockerfile 中不包括拷贝命令)
$ docker build .
# -t 参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是 latest
$ docker image build -t nginx-demo:0.0.1 .
等待镜像构建完成,看一下镜像列表,发现刚创建的镜像没有仓库和 tag 信息:
$ docker images
刚才说了可以构建镜像的时候指定,也可以构建之后再添加:
$ docker tag <镜像ID> <镜像仓库+镜像名>:<版本信息>
# 如果省略标签,则默认是 latest
$ docker tag <镜像ID> <镜像仓库+镜像名>
$ docker run -it -p 8080:80 <镜像ID>
新开个终端, docker ps
可以看到已经运行的容器。
然后浏览器中访问:
搭建 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
然后 push 刚才的镜像:
docker push 127.0.0.1:5000/nginx-demo:0.0.1
访问本地镜像仓库提供的 API,获得 nginx-demo 镜像的 tag 列表:
http://localhost:5000/v2/nginx-demo/tags/list
也可以 pull,但因为本地已经有了该镜像,所以会提示已经是最新(可以删了镜像 再 pull 试试):
docker pull 127.0.0.1:5000/nginx-demo:0.0.1
- —registry-mirror 可以为 docker 客户端指定镜像地址,在客户端的设置中添加
- —insecure-registry 仓库没有 HTTPS 的话,添加该标记以通过 HTTP 来访问