一、Docker的介绍
1.1 简介
Docker 是基于Go开发的开源应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux或Windows 等机器上,也可以实现虚拟化。
1.2 解决的问题
- 环境不一致
- 多用户的操作系统下相互影响
- 运维成本高
- 安装软件成本过高
1.3 Docker的优势
资源利用率高
容器里的应用就是底层系统的一个进程,而不是一个操作系统,自然对系统资源的利用率更高。
启动快
容器里的应用直接运行于宿主内核,启动容器相当于启动本机的一个进程,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。极大的节约了开发、测试、部署的时间。
一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发、测试、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker
的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
持续交付和部署
使用 Docker
可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过Dockerfile
来进行镜像构建,并结合持续集成进行集成测试,而运维则可以直接在生产环境中快速部署该镜像,甚至结合持续部署系统进行自动部署。
提供弹性的云服务
Docker 容器可以随开随关,很适合动态扩容和缩容。
组建微服务架构
通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
1.4 Docker 的思想
-
镜像 (Image)
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。
-
容器(container)
容器可以理解成是镜像的实例。镜像是静态的,容器是镜像运行时的实体,可以被创建、启动、暂停、删除等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器内的进程运行在一个隔离的环境里,拥有自己的
root
文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。 -
仓库(Repository)
镜像构建完成要管理、共享,就需要一个集中存储、分发镜像的服务。Docker Registry 就是这样的服务。可以将Docker Registry理解成Github。一个 Docker Registry 中可以包含多个仓库(
Repository
);每个仓库可以包含多个 标签(Tag
);每个标签对应一个镜像。
二、安装Docker
以下操作以mac OS为例。windows也很简单,下载docker安装包,安装,启动即可。
2.1 安装 Homebrew
如果没有安装Homebrew,执行下面命令进行安装:
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
Homebrew 是 macOS 或 Linux缺失的软件包管理器。可以安装Apple(或您的 Linux 系统)没有预装但 你需要的东西。
Homebrew Cask 扩展了 Homebrew,可以优雅、简单和快速的安装 mac OS 的 GUI 应用程序。
2.2 安装Docker
2.2.1 brew cask 安装
$ brew cask install docker
检查是否安装成功:
$ docker --version
$ Docker version 19.03.13, build 4484c46d9d
$ docker-compose --version
$ docker-compose version 1.27.4, build 40524192
$ docker info
如果都执行正常执行的话说明安装成功。
2.2.2 手动下载安装
2.3 镜像加速
国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了加速器服务,例如:
阿里云加速器(点击管理控制台 -> 登录账号(淘宝账号) -> 右侧镜像中心 -> 镜像加速器 -> 复制地址)
我使用的是网易云和百度云,因为无需登录认证就可以下载使用。
2.3.1配置
打开Docker应用,点击设置按钮,点击左侧的Docker Engine,编辑 json 文件(如下)。修改完成之后,点击 Apply & Restart
按钮,Docker 就会重启并应用配置的镜像地址了。
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
验证配置是否生效:
$ docker info
信息中看到如下说明配置成功了
Registry Mirrors:
https://hub-mirror.c.163.com/
https://mirror.baidubce.com/
三、操作镜像
3.1 基本指令
获取镜像
$ docker image pull [选项] 仓库名[:标签]
例:
$ docker image pull library/hello-world
docker image pull
是拉取镜像的命令- 选项:具体可通过docker pull --help 查看,包括
-a
,-q
等library/hello-world
是image文件在仓库里面的位置,library是 Image 文件所在的组,hello-world是 Image文件的名字。Docker 官方提供的 Image 文件,都放在library组里面,是默认组,所以可以省略library。- 标签:镜像版本号 默认
latest
以上可以简写成:
$ docker image pull hello-world
查看镜像
查看本机所有镜像:
$ docker iamge ls
删除镜像
$ docker image rm [OPTIONS] IMAGE [IMAGE...]
docker image rm
删除一个或多个镜像- OPTIONS
- --force, -f 强制删除
- --no-prune 不删除未标记的父项
- IMAGE:可以是镜像名、镜像ID、镜像摘要
四、操作容器
4.1 新建并启动
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# 或
$ docker container run [OPTIONS] IMAGE
注意:docker run 命令具有自动抓取 Image 文件的功能。如果发现本地没有指定的 Image 文件,就会从远程仓库自动抓取。所以
docker image pull
命令并非必须。
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
基于hello-world镜像创建一个容器:
$ docker run hello-world
以上信息输出后,容器就会自动终止。
有些容器不能终止,因为是提供的服务或需要交互。
比如需要进入node环境并执行任务:
$ docker run -it --rm node bash
-
-it
这是两个参数,
-i
:交互式操作,-t
是 终端。这里打算进入bash
执行一些命令并查看返回结果,因此我们需要交互式终端。
以上可以看出已经创建了容器并可以在shell下操作,比如进入Node环境,执行操作,比如定义常量a并打印a
-
--rm
这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动
docker container rm
。我们这里只是随便测试一下命令看看结果,不需要排障和保留结果,因此使用--rm
可以避免浪费空间。 -
bash
这里我们希望有个交互式 Shell,因此用的是
bash
对于交互式容器,需要使用exit
或 Ctrl+d
指令退出。
4.2. 查看本机容器
4.2.1 本机正在运行的容器
$ docker container ls
4.2.2 本机所有容器,包括停止运行的
$ docker container ls --all | -a
本机所有容器:刚才终止运行的hello-world 和 node
4.3 终止运行的容器
4.3.1 docker container kill
$ docker container kill [CONTAINER ID]
4.3.2 docker container stop
$ docker container stop [CONTAINER ID]
4.4 重启已终止的容器
$ docker container start 1aaf8fd9dfd4
4.5 删除容器
4.5.1 删除处于终止状态的容器
删除一个处于终于状态的容器:
$ docker container rm [CONTAINER ID]
比如,删除node容器:
$ docker container rm 520606897c06
就剩一个hello-world容器了。
4.5.2 删除运行中的容器
如果要删除一个处于运行中的容器,可以添加 -f
参数。Docker 会发送 SIGKILL
信号给容器。
$ docker container rm -f [CONTAINER ID]
4.5.3 清理所有处于终止状态的容器
$ docker container prune
4.6 导入导出
4.6.1 导出容器
如果要导出本地某个容器,可以使用 docker export
命令。
比如导出 hello-world 容器
$ docker export 14c34720f4f1 > hello-world.tar
这样将导出容器快照到本地文件:
4.6.2 导入容器快照
使用 docker import
从容器快照文件中再导入为镜像,例如:
$ cat hello-rorld.tar | docker import - test/hello-world:1.0
五、Dockerfile 定制镜像
定制镜像需要Dockerfile 文本文件,其内包含了一系列指令。
1. 新建一个Node项目 my_http
2. 创建 .dockerignore
$ touch .dockerignore
3. 编辑 .dockerignore
.dockerignore
.git
.gitignore
node_modules
4. 创建Dockerfile文件
$ cd my_http
$ touch Dockerfile
5. 编辑Dockerfile
FROM node:12.16.0
COPY . /app
WORKDIR /app
RUN npm install
EXPOSE 3000
-
FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。而
FROM
就是指定 基础镜像,因此一个Dockerfile
中FROM
是必备的指令,并且必须是第一条指令。除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为
scratch
。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。FROM scratch ...
-
COPY . /app
将当前目录下的所有文件(除了
.dockerignore
排除的文件),都拷贝进入 image 文件的/app
目录 -
WORKDIR /app
指定接下来的工作路径为
/app
-
RUN npm install
在
/app
目录下,运行npm install
命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。 -
EXPOSE 3000
将容器 3000 端口暴露出来, 允许外部连接这个端口
6. 构建镜像
$ docker image build [OPTIONS] PATH | URL | -
在项目根目录下执行:
$ docker image build -t my_image:1.0 .
-
docker image build
构建镜像 -
-t
指定 Image 文件的名字,后面可以用冒号指定标签。如果不指定,默认的标签就是latest
-
.
点表示 Dockerfile 的上下文路径
7. 检查是否构建成功
$ docker image ls
8. 创建容器
$ docker container run -p 8000:3000 -it my_image:1.0 bash
-
-p
参数容器的 3000 端口映射到本机的 8000 端口
-
-it
参数 容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器
-
my_image
image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。
-
bash
容器启动以后,内部第一个执行的命令。这里是启动 bash,保证用户可以使用 Shell
9. 运行项目
创建容器之后,进入app目录下,并打开shell,执行ls
可以查看当前容器下的文件,接下来执行node index.js
,在浏览器访问localhost:8000
9. CMD命令
以上案例,容器启动以后,需要手动输入命令node index.js
。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。
FROM node:12.16.0
COPY . /app
WORKDIR /app
RUN npm install
EXPOSE 3000
CMD node index.js
注意:指定了
CMD
命令以后,docker run
命令就不能附加命令了(比如bash),否则会覆盖CMD
命令。
启动容器:
$ docker run -it --rm -p 8000:3000 my_http_image:1.1
CMD 和RUN的区别
RUN
命令在 Image 文件的构建阶段执行,执行结果都会打包进入 Image 文件;
CMD
命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN
命令,但是只能有一个CMD
命令。
六、仓库
6.1 搜索、拉取
1. 搜索镜像
通过 docker search
命令来查找官方仓库中的镜像,并利用 docker pull
命令来将它下载到本地。
docker search
必须要加一个关键词,如:
$ docker search nginx
返回了很多包含关键字的镜像,其中包括镜像名字、描述、收藏数、是否官方创建(OFFICIAL)、是否自动构建 (AUTOMATED)。
根据是否是官方提供,可将镜像分为两类。
一种是类似nginx
这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。
还有一种类型,比如 bitnami/nginx
镜像,它是由 Docker Hub 的注册用户创建并维护的,往往带有用户名称前缀。可以通过前缀 username/
来指定使用某个用户提供的镜像。
另外,在查找的时候通过 --filter=stars=N
参数可以指定仅显示收藏数量为 N
以上的镜像。
2. 拉取镜像
$ docker pull
6.2 Docker Hub
Docker 官方维护了一个公共仓库 Docker Hub,大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
1. 注册
可以在 https://hub.docker.com 免费注册一个 Docker 账号。
2. 登陆
通过执行 docker login
命令交互式的输入用户名及密码来完成在命令行界面登录 Docker Hub。
通过 docker logout
退出登录。
3. 推送
首先为本地的 image 标注用户名和版本
$ docker image tag [imageName] [username]/[repository]:[tag]
# 例:
$ docker image tag my_http_image:1.0 cuilldocker/my_http_image:1.0
也可以不标注用户名,重新构建一下 image 文件。
$ docker image build -t [username]/[repository]:[tag] .
# 例:
$ docker image build -t cuilldocker/my_http_image:1.0 .
最后推送:
$ docker image push [username]/[repository]:[tag]
# 例:
$ docker image push cuilldocker/my_http_image:1.0
至此,关于Dokcer的基本操作/基础暂告一段,以后抽时间会学习怎么用Docker搭建私有仓库、网站、CI/CD。