<style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
- 根据官网描述,docker 是一个容器平台,是标准化的软件单元,使用了虚拟化技术(cgroup:提供容器隔离;UnionFS:保存镜像并使容器变得短暂),基于 Google 推出的 go 语言实现的开源项目,代码在 GitHub 上进行维护。
-
快速交付和部署
- 轻快:一次创建或配置,可在任意地方正常运行,秒级启动,节约开发、测试、部署时间。
-
高效虚拟化
- 基于内核的虚拟化,不需要额外 hypervisor 支持,CPU/内存的低消耗,更高效。
-
可移植、可扩展
- 物理机、虚拟机、公有云、私有云、个人电脑、服务器等平台均可以运行
-
对比传统虚拟机
特性 容器 虚拟机 启动 秒级 分钟级 硬盘使用 一般 MB 一般 GB 性能 接近原生 弱于原生 系统支持量 单机上千个容器 一般几十个 -
可以总结出,docker 可以实现:
- 隔离应用依赖
- 创建应用镜像并进行复制
- 创建易分发的即启即用的应用
- 允许实例简单、快速扩展
- 测试应用并随后销毁
可见 docker 的 野心 是创建 ===软件程序可移植的轻量容器===,让其可以在任何安装了 docker 的机器上运行,而不用关心底层操作系统。
先了解一下几个基本概念:
镜像:是一个只读的模版,用来创建 docker 容器,容器在启动的时候创建一层可写层作为最上层
容器:从镜像创建的运行实例,可以被启动、开始、停止、删除。容器间是相互隔离的,看上去是一个简易版的 Linux 环境(包括 root 用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序
仓库:类似 git,集中存放镜像文件的场所,分为公开仓库(Public)和私有仓库(Private),最大的公开仓库是 Docker Hub
注册服务器:类似 GitHub 这样的托管服务,存放着多个仓库
宿主机:docker 所在的服务器
数据卷:可供一个或多个容器使用的特殊目录,类似于 Linux 下对目录或文件进行 mount,它绕过 UFS,可以提供很多有用的特性:
- 在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新,不会影响镜像
- 卷会一直存在,直到没有容器使用
网络模式:用来实现容器的网络通信,大概包括五种:
- bridge 模式,--net=bridge(默认)
- host 模式,--net=host
- none 模式,--net=none
- 其他容器模式(即 container 模式),--net=container:NAME_or_ID
- 用户自定义:docker 1.9 版本以后新增的特性
Dockerfile:易于自动化的命令,包含创建镜像所需的全部指令,基于 dockerfile 中的指令,我们可以使用
$ docker build
命令来创建镜像,通过减少镜像和容器的创建过程来简化部署。语法命令:
INSTRUCTION argument 指令不区分大小写,但命名约定为全部大写
FROM
- 格式为
FROM <image>
或FROM <image>:<tag>
- 第一条指令必须为
FROM
指令。并且,如果在同一个 Dockerfile 中创建多个镜像时,可以使用多个FROM
指令(每个镜像一次)MAINTAINER
- 格式为
MAINTAINER <name>
,指定维护者信息RUN
- 格式为
RUN <command>
或RUN ["executable", "param1", "param2"]
- 前者将在 shell 终端中运行命令,即
/bin/sh -c
;后者则使用exec
执行。指定使用其它终端可以通过第二种方式实现,例如RUN ["/bin/bash", "-c", "echo hello"]
- 每条
RUN
指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行CMD
CMD ["executable","param1","param2"]
使用exec
执行,推荐方式CMD command param1 param2
在/bin/sh
中执行,提供给需要交互的应用CMD ["param1","param2"]
提供给ENTRYPOINT
的默认参数- 指定启动容器时执行的命令,每个 Dockerfile 只能有一条
CMD
命令。如果指定了多条命令,只有最后一条会被执行- 如果用户启动容器时候指定了运行的命令,则会覆盖掉
CMD
指定的命令EXPOSE
- 格式为
EXPOSE <port> [<port>...]
- 告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口
ENV
- 格式为
ENV <key> <value>
。 指定一个环境变量,会被后续RUN
指令使用,并在容器运行时保持。ADD
- 格式为 ADD
<src> <dest>
- 该命令将复制指定的
<src>
到容器中的<dest>
。 其中<src>
可以是 Dockerfile 所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)COPY
- 格式为
COPY <src> <dest>
- 复制本地主机的
<src>
(为 Dockerfile 所在目录的相对路径)到容器中的<dest>
。当使用本地目录为源目录时,推荐使用COPY
,能用COPY
的情况下不用ADD
ENTRYPOINT
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
(shell 中执行)- 配置容器启动后执行的命令,并且不可被
docker run
提供的参数覆盖- 每个 Dockerfile 中只能有一个
ENTRYPOINT
,当指定多个时,只有最后一个起效VOLUME
- 格式为
VOLUME ["/data"]
- 创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
USER
- 格式为
USER daemon
- 指定运行容器时的用户名或 UID,后续的
RUN
也会使用指定用户- 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres
。要临时获取管理员权限可以使用gosu
,而不推荐sudo
WORKDIR
格式为
WORKDIR /path/to/workdir
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录
可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
则最终路径为 /a/b/c
ONBUILD
格式为
ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令
例如,Dockerfile 使用如下的内容创建了镜像
image-A
:[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/node-build --dir /app/src [...]
如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像时,会自动执行 ONBUILD 指令内容,等价于在后面添加了两条指令:
FROM image-A #Automatically run the following ADD . /app/src RUN /usr/local/bin/node-build --dir /app/src
使用
ONBUILD
指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild
编写完成 Dockerfile 之后,可以通过
$ docker build
命令来创建镜像
- 基本的格式为
$ docker build [选项] 路径
,该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下所有内容发送给 Docker 服务端,由服务端来创建镜像。因此一般建议放置 Dockerfile 的目录为空目录。也可以通过.dockerignore
文件(每一行添加一条匹配模式)来让 Docker 忽略路径下的目录和文件- 例如:
$ docker build -t ${dockerImageName} --force-rm -f ./Dockerfile .
=========================================================
以上是一些基本概念,现在 ubuntu 下开始安装 docker 并启动一个 nginx 容器(其实大多数场景下 nginx 没必要跑在容器里,这里只是举个例子)
=========================================================
$ cat /etc/issue
Ubuntu 16.04.6 LTS \n \l
-
通过 shell 命令安装:
$ curl -sSL https://get.docker.com/ | sh
- 更多平台及安装方式
-
检验安装,显示版本信息,说明已成功安装:
$ docker -v Docker version 18.09.5, build e8ff056
ps:
$ docker info
可查看更多信息 -
下面开始创建一个容器:
$ docker run❶ \ -d❷ \ --name=demo❸ \ -u root❹ \ -p 8002:80❺ \ -v /var/demo:/var/demo❻ \ nginx:latest❼
该命令表示:基于 nginx:latest 这个镜像,创建一个名称为 demo 的容器,并把容器内部的 80 端口与宿主机上的 8002 端口做映射,使得通过宿主机 8002 端口的流量转发到容器内部的 80 端口上
❶:
run
新建并启动容器,更多选项,其标准过程:- 检查本地是否存在指定的镜像,不存在就从公有仓库下载(docker pull xxx)
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
❷:
-d
Daemonized 模式,以守护态形式在后台运行容器
❸:
--name=demo
为容器起一个名字
❹:
-u
指定容器的用户
❺:
-p
端口映射,规则是 -p 宿主机端口:容器端口,可多次使用映射多个端口
❻:
-v
挂载数据卷,规则是 -v 宿主机目录:容器目录,可多次使用挂载多个数据卷
❼:镜像名,该容器所用的镜像名,可通过
$ docker images
查看本地镜像 -
查看正在运行的容器:
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c24cfee8226a nginx:latest "nginx -g 'daemon of…" 6 minutes ago Up 6 minutes 0.0.0.0:8002->80/tcp demo
ps:
$ docker ps -a
查看所有容器(包括正在运行的、已停止的)现在访问宿主机的 8002 端口(安全组开通),即可看到 nginx 的欢迎页面:
-
进入容器:
执行
$ docker exec -it demo bash
,demo 也可以换成容器的 id 即:$ docker exec -it c24cfee8226a bash
在容器内可执行
$ netstat -lntp
查看端口使用情况:Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/nginx: master pro
若发现 netstat not found,先执行
$ apt update && apt install net-tools
执行
$ exit
退出容器ps:
$ docker inspect demo
可以查看该容器更多信息$ docker stop 容器名/id
终止容器$ docker rm 容器名/id
删除未运行的容器$ docker rmi 镜像名/id
删除未占用(无容器正在运行)的镜像$ docker rmi $(docker images -f "dangling=true" -q)
批量删除为none
(无容器正在运行)的镜像
【参考】:
- https://www.kancloud.cn/kancloud/docker-guide/220859
- http://leilux.github.io/lou/docker_practice/introduction/README.html
- https://docs.docker.com
- https://blog.csdn.net/ithaibiantingsong/article/details/81386307
===🧐🧐 文中不足,欢迎指正 🤪🤪===