Docker 基础

学习条件:下载 Docker Desktop

Docker 是什么

Docker 是这样介绍自己的:

an open source project to pack,ship and run any application as a lightweight container.

是一个将任何应用作为轻量级的容器进行打包、发布和运行的开源项目

Nodejs 是这样介绍 docker 的:

allows to package an application with all of its dependencies into a standardized unit.

允许将应用及其所有依赖打包到一个标准的单元里

Docker 可以被粗糙地被理解为一个轻量的虚拟机。但是它跟虚拟机有一些不同:

image-20221125183547596

不同点为以下内容:

  • VM 在宿主上虚拟出一层 Hypervisor ,它虚拟出了硬件。在硬件环境上,安装完全独立的 Guest OS(虚拟机里的系统),我们的应用程序会在里面运行。Docker 是利用了 Host OS(物理机里的系统)里的 nameSpace、control group 等将应用程序分离,让它们跑在 Docker Engine 中。
  • 由于 Docker 没有虚拟层,所以会比虚拟机轻量很多,包括内存、运行速度等都会快很多。

配置 Docker

国内从 Docker Hub 拉取镜像有时会遇到困难,需要额外配置镜像加速器。

国内很多云服务商都提供了国内加速器服务,这里就以网易云和百度云为例,设置国内镜像源:

打开 Docker 后点开 Preferences => Docker Engine =>编辑 daemon.json

添加国内镜像

json
1{
2  ...省略部分内容,
3  "registry-mirrors": [
4    "https://hub-mirror.c.163.com",
5    "https://mirror.baidubce.com"
6  ]
7}

Docker 架构图

img

Docker_Host 为 Docker 运行的宿主机,这个宿主机上会安装有 Docker daemon。

Docker daemon 负责做各种 docker 操作,比如下载镜像、运行容器等。

我们通过命令行指令的方式与 Docker daemon 交互。如:docker build、docker pull、docker run 等。

daemon 也可以跟 Registry 交互。Registry 是 docker 使用者分享镜像用的。

四大组成对象

Docker 体系中,有四大组成对象(Object),所有的 Docker 的功能以及周边生态都围绕它们展开,他们分别是:镜像(Image)、容器(Container)、网络(Network )、数据卷(Volume)。

下图是 Docker Desktop 的界面,已经展示出来三大对象了。

2024-03-20.164657

images 是什么

当运行一个容器时,它会使用一个隔离的文件系统,这个自定义的文件系统是镜像(Image)提供的。可以理解成 Image 是一个只读的文件包,它包含了虚拟环境运行最原始文件系统的内容。

镜像包含了容器的文件系统,所以它必须包含运行应用程序所需的所有东西——所有依赖项、配置、脚本、二进制文件等等。该映像还包含容器的其他配置,例如环境变量、要运行的默认命令和其他元数据。

使用以下命令行可以查看镜像列表

bash
1docker image ls

当然,也可以通过 docker 桌面端查看。

Container 是什么

简单来说,容器(container)是我们的计算机上的一个进程,已与主机上的所有其他进程隔离。在 Docker 里,它也被引申为隔离出来的虚拟环境。

如果把镜像理解成类,那么容器就是类的实例。镜像内放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成了一个活的空间。

容器的特点:

  1. 是一个镜像(image)的可运行实例。我们可以创建、启动、停止、移动或者删除容器

  2. 可以运行在本地机、虚拟机或者部署到云上。

  3. 可移植的,能够被任何操作系统运行

  4. 容器之间互相隔离,运行他们自己的软件、二进制文件和配置

Network 是什么

容器和容器之间是需要交互的,这里的交互大多数情况指的是数据信息交换。

Network 是 Docker 中非常强大的功能,我们能够用它对各个容器之间的网络进行配置,还可以在容器之间建立虚拟网络,将数个容器包括在内,同时与其他网络环境隔离。

另外,Docker 能够在容器中营造独立的域名解析环境,这使得我们可以在不修改代码和配置的前提下直接迁移容器。

Volume 是什么

除了网络外,文件也是重要的数据交互的资源。我们通常会利用虚拟机或者容器的文件系统作为应用数据等文件的存储位置。然而这种方法并非是完全安全的,因为当容器或者虚拟机出现问题导致文件系统无法使用时,之前存放的数据也就消失了。

为了保证数据的独立性,我们可以把宿主机的文件目录挂载到容器的文件目录中,还可以建立一个独立的目录持久存放数据,或者在容器之间共享。

这几种方式进行的持久化数据,我们称之为数据卷(Volume)。

通过 Desktop 操作 Docker

通过 Images 生成 Container

搜索一个镜像并将其 pull 到本地。

image-20240320164550623

pull 到本地后,直接点击 run,使它变成 container。

image-20240320165133903

在 run 之后可以填写一些参数

image-20240320165252314

nginx 镜像的 container 的参数基本都是可选的:

  1. container name:如果不填则会生成一个随机的。

  2. ports:端口号。容器的端口号是 80,需要你填写的端口号是宿主机的端口号,也就是说把宿主机的端口号映射到容器的 80 端口号才可以访问。

  3. volume:数据卷。默认情况容器的数据会随着容器的销毁而销毁,如果指定了数据卷,会把数据保存在宿主机,这样数据也可以挂载到新容器中,相当于实现了数据持久化。

    这里需要将宿主机的目录挂载到容器中保存数据的目录中,这样容器产生的数据就会写到宿主机的目录里。

  4. 环境变量:没什么好说的。

示例:

image-20240320170344633

这里将宿主机的/temp/nginx/html挂载到 nginx 容器的usr/share/nginx/html目录中。

每种镜像(nginx、mysql 等)存储数据的目录都不一样,需要自行查阅。

点击 Run 之后 nginx 容器就跑起来了。

image-20240320172242254

现在往挂载的宿主机目录中存入一个 index.html 文件。

image-20240320172355203

再打开http://localhost:3333/就可以访问到 nginx 容器内 80 端口的 index.html

image-20240320172523625

这说明我本地宿主机的目录已经成功挂载到 docker-nginx 容器内的目录了,一个简单的 基于 nginx 的 web 环境搭建完成。

Volume 挂载到容器

点击 files,可以查看到容器内部的文件系统。

image-20240320201343235

MOUNT 是挂载的意思,意思是这个目录挂载到了 Volume 中。

Volume 可以是自己指定的宿主机目录,也可以是 Docker 帮我们生成的目录(只能由 docker 进程编辑和修改)。

我们在/temp/nginx/html中新创建一个 file,会马上影响到容器内部。

bash
1cd ~/temp/nginx/html
2touch index.txt

image-20240320201900516

这就是 Volume 挂载的作用。

如果挂载某些目录报错了,那是因为 docker 挂载的目录是需要配置的,在 Settings > Resources > File Sharing 里加一下就行:

image-20240320202104673

不同的 Image 生成的容器,它的数据会保存到不同的目录中。

因此如果想要挂载 Volume,就需要通过镜像搜索页的说明找到该容器的目录。

以 nginx 为例,它的官方说明的目录挂载点是这样的:

image-20240320202629467

nginx 的配置文件的目录是这里:

image-20240320202845687

上面的命令行意思 是通过命令行 docker run 来跑镜像, -v 是指定挂载的数据卷,后面的 :ro 代表 readonly,也就是容器内这个目录只读,:rw 表示容器内可以读写这个目录。

exec 在容器内执行命令

如果想要在容器内执行命令,在 Exec 这个界面就可以做到。

image-20240322103608312

inspect 查看容器配置

通过 inspect 可以查看容器的配置,这是一个 JSON 对象。

下图示例:查看容器的挂载

image-20240322110306927

通过命令行操作 Docker

概览

结合上面的 Desktop,我们已经基本对 Docker 有所了解。

服务器里的 Docker 可没有可视化界面,所以就需要用到命令行,以下所有的命令都能在 Desktop 中找到对应的操作。

常用的命令行如下,这些都是前缀命令,表示做什么事情。

命令用途
docker pull获取 image
docker build创建 image
docker images列出 image
docker run从 image 创建并运行 container
docker ps罗列正在运行的 container,-a 罗列出所有
docker rm删除 container
docker rmi删除 image
docker cp在主机 和 container 之间拷贝文件
docker commit保存改动为新的 image
docker exec -it进入容器并让容器运行我们给出的命令

仅仅有前缀命令还不够,我们还需要结合参数。

docker pull

我们能够通过Docker Hub访问线上的镜像,比如版本号、镜像名、功能等,再通过 docker pull 命令在本地终端拉取镜像库里的镜像。

以获取 mysql 的 image 为例

bash
1-- 获取最后一个版本的镜像
2docker pull mysql
3-- 获取最后一个版本的镜像 以 :TAG 结尾
4docker pull mysql:latest
5-- 拉取指定版本的镜像 以 :TAG 结尾
6docker pull mysql:5.7.28

image 就相当于一个模板,运行 image 可以产生一个容器。

建议在使用镜像时指定版本,因为默认的 latest 是滚动更新的,现在下载的 latest 版本过一段时间就不一定是最新的版本了,所以会造成混淆,弄不清到底是哪个版本。

docker images

查看本地所有 images(镜像)

bash
1docker images

image-20221126110724414

docker ps

查看本地所有容器

bash
1docker ps -a

查看本地正在运行的容器

bash
1docker ps

这个命令相当于 Docker Desktop 的首页。

image-20221126113644843

docker run

docker 上创建并运行一个容器的命令示例

bash
1docker run mysql

如果本地没有容器需要的 image,则会从 registry 中拉取 image 并生成容器。

拉取 image 成功后会有提示

bash
1Digest: sha256:96439dd0d8d085cd90c8001be2c9dde07b8a68b472bd20efcbe3df78cff66492
2Status: Downloaded newer image for mysql:latest

每次运行 docker run xxx 都会产生一个新的容器,如果没有指定容器的名称则默认生成

docker inspect

查看容器详细信息

bash
1docker inspect <Container ID>

通过这个命令可以看到容器的详细信息,比如端口号,ip 地址等。

运行 mysql 容器示例

以下为运行 mysql:5.7.28 的 docker 命令示例 (来自 dockerhub-mysql官方文档)

运行 mysql:5.7.28 容器

bash
1docker run --name local-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7.28
  • -- name local-mysql —— 指定容器名称为 local-mysql

  • -d - 在后台运行,可以指定版本如:mysql:5.7.28。没写版本则同mysql:latest,指定最新的版本。

    没有 -d 这个参数就表示前台运行,当退出终端后,就访问不到了。因此大多数情况下都会用到 -d

  • -p 3306:3306 -将主机 3306 端口映射到容器 3306 端口

    -p不单单可以绑定单个端口,也可以绑定端口范围,前后必须对应

    bash
    1-p 8080-8090:8080-8090 公开端口范围
    2-p 192.168.56.106:8080:80 如果宿主机有多个 ip,可以指定绑定到哪个 ip
  • -e MYSQL_ROOT_PASSWORD=123456 设置 env

当启动完成会返回容器的 ID

bash
11c17b934e7b5bec7b7481f9ac8a03ca93aabfb621b840de8f12ce94cf957943f

当容器在本地跑之后,docker 允许使用-it参数以命令行的方式跟容器进行交互。

比如下面就是用命令重新创建一个新的 mysql 客户端容器,并与刚才实例出来的 mysql 容器连接。

bash
1docker run -it --rm mysql:5.7.28 mysql -hsome.mysql.host -usome-mysql-user -p
  • -it docker 使用命令行交互方式与容器交互,可以在控制台中输入、输出
  • --rm 当容器退出时自动删除容器。一般是在使用客户端程序时使用此参数,如果每次使用客户端都创建一个新的容器,会占用大量的系统空间,所以会用完后删除容器。
  • mysql:5.7.28 表示容器的镜像
  • mysql -hsome.mysql.host -usome-mysql-user -p —— 启动该容器时执行的命令
  • -hsome.mysql.host——完整为-h 容器的ip
  • -usome-mysql-user —— 完整为-u 容器的用户名

通过docker inspect查看到具体 ip 地址后完整填入命令行

bash
1docker run -it --rm mysql:5.7.28 mysql -h172.17.0.2 -uroot -p

最后输入密码,即可访问之前创建的 local-mysql 的容器。

docker stop

停止容器

bash
1docker stop <Container ID>

docker start

启动已经存在的容器

bash
1docker start <Container ID>

docker exec -it

与 docker 容器的交互命令模式下,在 container 中使用 bash

bash
1docker exec -it <Container name> /bin/bash
2-- 退出
3exit

docker cp

将主机上的文件拷到容器中

bash
1docker cp <host-file-path> <Container ID>:<Container path>

示例:

bash
1cd Desktop && mkdir mysql-config
2cd mysql-config && touch mysql-config.cnf
3echo -e "# this is mysql configuration file" >> mysql-config.cnf
4docker cp ~/Desktop/mysql-config/mysql-config.cnf 47dbc3b110cf:/etc/mysql/conf.d/mysql-config.cnf

docker rm

删除容器

bash
1docker rm <Container ID>

docker rmi

删除 image

bash
1docker rmi <Image ID>

总结

Docker 可以把环境封装成镜像,镜像跑起来之后就是一个独立的容器。通过这种方式可以快速部署多个相同的实例。

Docker 提供了一个 Desktop 工具,可以让我们在本地可视化地操作 docker。

这些可视化的操作都有对应的命令,当服务器上没有桌面的时候,就需要用命令行操作了。