Docker 的个人学习记录。不包含 Docker 安装内容(默认已完成)。
1. Docker 的意义
介绍 docker 的文章实在太多了,所以这里就不长篇累牍地展开。简而言之,往大的方向说,企业可以通过使用容器工具 docker 和容器编排调度工具部署微服务应用、实现 DevOps 的交付方式;往小的方向说,在个人开发环境中使用 docker 是各种省心。
举例来说,我在本地开发环境为 MacOS、需要安装 Redis, 那么我可以选择从 Github 下载源码并编译,或通过 Homebrew 进行安装和各种环境变量的配置、或者下载 dmg 文件进行安装(如果有的话)。如果进一步想要使用不同的版本,并且在不同版本之间来回切换,在不使用 docker 的情况下各种配置真是让人头大。但是通过 docker, 我只需要下载不同版本的镜像并启动相应容器。如果期间有什么配置不满意,直接把容器删除即可。当某个软件版本过久已经彻底不想用了,则直接删除容器和镜像,再也不用操心哪里的配置没有删干净,简直是轻松愉快。
2. 官方教程
如果是从零开始学习,我比较推荐从官方教程开始,因为其中包含了容器的构建和发布、数据绑定(volume)、容器网络(network)和多容器应用 (docker-compose)的使用,涵盖了大部分基本使用场景。
运行官方教程:
1 | docker run -d -p 80:80 docker/getting-started |
该命令的解释:
docker run
为启动 docker 容器的命令。-d
即--detach
,表示容器以后台进程的方式运行。-p 80:80
指定宿主与容器的端口映射关系,即host-port:container-port
。docker/getting-started
为镜像的名称。实际上完整的镜像名必须包含 tag,在此处 tag 被隐藏掉,默认值为 latest。即该镜像名等价于docker/getting-started:latest
如果本地没有 docker/getting-started:latest
的镜像,docker 会自动下载。
容器启动后,在浏览器中访问 http://localhost
即可。
3. 主要概念和常用命令
主要名词:
- 镜像 image: 可类比为一个软件的名称,或 OOP 中的类的概念。如 redis:
docker pull redis
。 - 标签 tag: 可类比为该软件的不同版本。如 redis 镜像相应的 tag 有: latest, 6.0, 5.0等不同版本。
- 容器 container: 基于镜像和 tag 启动的虚拟容器,可类比为 OOP 中的对象实例。一个运行中的容器就相当于一台完备的运行中的 Linux 服务器。
- volume: 允许容器共享宿主的目录或文件,避免容器销毁后内部数据丢失。分为交由 docker 管理(Named Volumes)和自己指定目录(Bind Mounts)两种方式。
- network: 允许不同容器之间通过指定 network 来进行通讯。
- docker-compose: 将多个 docker 容器组合运行。
常用的命令:
--help
或-h
: 查看命令的解释,可一直往下展开,如:docker --help
,docker image --help
,docker image ls --help
。docker image
镜像相关操作docker image ls
: 显示本地下载的镜像,等价于docker images
.docker image rm <image-id|image-name>
: 删除已下载的镜像
docker run
: 运行容器-v
: 指定 volume, 如-v $pwd:/container/path/
--name
: 指定容器名,如果不指定则由 docker 随机生成。--network
: 指定容器之间的通讯网络。
docker build
: 根据 Dockerfile 构建镜像。
4. demo 示例: 演示镜像构建及发布的过程
Demo 目标:用尽量小的内容演示完整的镜像构建过程。
- 定义一个在指定时间内打印内容的 shell script: counting.sh。
- 将脚本打包,创建我们自己的镜像。
- 运行容器,得到期待的结果。
- 上传至 docker hub.
该 demo 可在任意目录进行。
一、创建脚本
创建一个文本文件 counting.sh
, 内容为:
1 | !/bin/sh |
脚本的内容非常简单:从 start
到 end
,每秒输出一次 start
,即运行时间为 end
秒,该值可自行调整。
设置 end
秒结束是顺便观察容器在命令执行完会自行中止的行为。
脚本完成后,设置运行权限:
1 | chmod u+x counting.sh |
Linux 文件权限不在本文讨论范围,因此默认为当前用户具有 root 权限,不再展开。
可通过命令 ./counting.sh
运行脚本,查看效果。
二、创建 Dockerfile
Dockerfile 相当于一个指导构件过程的描述文件,且在最后指定容器启动时运行的命令。
在当前目录创建文本文件 Dockerfile
, 内容为:
1 | FROM alpine:latest |
内容说明:
第一行 FROM
指令表明即将构件的镜像是基于 alpine:latest
镜像,可类比为 OOP 中类的继承。其中 alpine
指的是 Alpine Linux, 旨在使容器更节省空间。
第二行 COPY
指令,指的是在镜像构建过程中将当前宿主工作目录($pwd
)的 counting.sh 文件复制至镜像的根目录 /
.
第三行 CMD
指令,即为容器在启动时执行的命令。如果指定了多个 CMD
指令,则只有最后的生效。
三、构建镜像
构建的镜像名为 demo-image
, 版本名为 v1
:
1 | docker build -t demo-image:v1 . |
使用 docker build
命令构建镜像,-t
选项指定标签名,格式为 “image-name:tag-name”. 最后的一点 .
指出命令本次构建所需的 Dockerfile 所在的目录(当前目录)。
1 | 构建过程输出的部分内容 |
当完成构建时,通过 docker images
可查看到该镜像:
四、运行容器
命令:
docker run --name mycontainer demo-image:v1
说明:
使用 docker run
命令启动容器,--name
参数显式指定容器的名称为 mycontainer. 容器名如果不显式指定则会由 docker 随机生成。最后的参数 demo-image:v1
指定了运行的镜像名和标签名(即软件版本)。
容器运行结果:
同时 Docker Dashboard 也显示了 demo 容器 mycontainer
的运行状态:
注意:
容器名可用于各种命令,如移除容器docker rm -f <container-id|container-name>
。通过自定义的容器名,可以省去执行实际操作前先用docker ps
或docker container ls -a
查看 containerId 这一步。容器名可通过命令
docker container rename
进行修改。
五、发布至镜像仓库
Docker hub 是 docker 官方维护的镜像仓库。该步骤会将本地构建的镜像发布到该仓库。
- 注册并登录至 docker hub(过程略)。
- 在 docker hub 中点击 “Create Reposotiry” 按钮创建项目仓库,填写仓库名为 “demo-repo”. 右侧提示为镜像发布的命令。
- 本地命令行中登录:
docker login -u <your-user-name>
并输入密码。
- 生成本地镜像与远程仓库的映射:
docker tag demo-image:v1 scvthedefect/demo-repo:repo-v1
; 注意这里特意区分了本地与远程仓库的镜像名和标签名。 - 推送到远程仓库:
docker push scvthedefect/demo-repo:repo-v1
- 测试:打开 Play with Docker 网站,登录并新建实例(貌似要科学一下,否则部分资源加载不了)
可见在其他服务器中下载镜像和运行容器成功,测试完成。
5. 本地运行 MySQL
演示本地运行 MySQL, 版本号为 5.7.
- 在官方仓库 Docker Hub 中搜索 MySQL 项目,可勾选左侧的过滤器:已验证的发布者、官方镜像,或按分类筛选等。
- 点击搜索结果,在项目主页的标签页 “Tags” 找到想要的版本,并用
docker pull
命令下载。
- 启动 mysql 容器:
1 | docker run -dp 3306:3306 --name mysql57 -v ~/docker-data/mysql57/:/var/lib/mysql/ -e MYSQL_ROOT_PASSWORD=myRootSecret mysql:5.7 |
命令说明:
-dp 3306:3306
: 以后台进程方式运行、且绑定宿主 3306 端口与容器 3306 端口绑定。--name mysql57
: 自定义的容器名,方便后续操作无需先查 containerId.-v ~/docker-data/mysql57/:/var/lib/mysql/
: 使用 Bind Mount 的方式,将 mysql 内的数据目录映射到宿主目录(~/docker-data/mysql57
),即使该容器被删除,新运行的容器只要也指定该目录,即可实现数据的共享。-e MYSQL_ROOT_PASSWORD=myRootSecret
:-e
指定了容器的环境变量,具体的值为。此处相当于安装 MySQL 后登录时要提供 root 密码。该密码任意指定即可。mysql:5.7
: 镜像名与标签名。
- 登录容器并使用 mysql 的 root 账号及密码登录 mysql client:
docker exec -it mysql57 /bin/bash
命令说明:
docker exec <container> <command>
: 表示在容器内执行一条命令。-it
:--interactive
和--tty
的简写,即创建一个可交互的 tty 终端。- 此处的 shell 为
/bin/bash
, 对于基于 alpine 的镜像版本,可使用/bin/sh
或sh
退出容器:
ctrl + p + q
, 注意一定要按照顺序。其他
- 使用 Navicat 登录连接 mysql.
- 更多的 mysql 设置可参考 mysql 的 docker hub 主页。