打包你的开发环境:Docker 从入门到上瘾

在实际的软件开发与发布中,我们常常会遇到"代码在我的电脑上跑的好好的,在你的电脑上却bug频出"的现象。除去代码设计本身的问题,还有可能就是对方环境的问题。

这里的Docker,就可以完美的解决因为环境导致的问题。

【初识Docker🔍】

为什么Docker能解决环境问题呢?这是因为Docker使用了Linux中容器封装的原理,将我们电脑上所需的环境打包到一个镜像(image)中。

在实际使用的时候,调用镜像中的内容即可。

了解了基本原理以后,我们再来了解几个重要的知识点:

容器(container

说人话就是Docker使用了一种类似于虚拟机的技术,不过相较于虚拟机系统中完整的系统功能,镜像中包含的是一个极简的、仅可用于运行软件的操作系统。

如上图中所示,Docker中的每一个容器中都不包含完整的系统内核,而是依赖于宿主机(也就是运行容器的电脑)中的内核运行;而在虚拟机中,则是有一套完整的操作系统内核。
*

镜像(image

在Docker中,镜像相当于一个容器的安装工具,容器是通过镜像生成出来的。

简单来说,镜像就相当于是容器的模具,我们可以通过镜像来生成指定的容器。这两者的关系就是面向对象编程中的对象与实例化对象之间的关系,可以类比记忆一下。

其中,镜像A创造出来的容器A1、A2、A3中的内容是相同的,但是这三个容器的本身却是不同的。这就像是用模具制造了三个月饼,他们的样子是相同的,不过我们不能说这三个月饼是同一块月饼。

而镜像B也创造出了三个容器,镜像B与镜像A是隔离的,所以镜像B创造出的容器与A创造的容器毫不相干。
*

镜像仓库

前面我们知道了Docker中的镜像的作用,那么我们的镜像是否可以像是GitHub上的项目那样分享出去呢?

答案当然是可以的。

Docker中,我们可以将我们的镜像上传至镜像仓库中,这样其他人就可以将镜像拉取到自己的电脑中,并创建出自己的容器。

这种模式与git十分相似,两者的区别就是一个拉取的是项目源代码,需要在自己电脑上配置好所需的环境;而在Docker中,创建完成了对应的容器以后,就可以直接运行了。

这样,就有了官方镜像站:DockerHub

【安装Docker⏬】

接下来我们来看看各个系统中是如何安装Docker的。

Windows

  • 需要在Windows中安装Docker,我们要先来到Docker官网中的下载界面Docker Desktop: The #1 Containerization Tool for Developers | Docker

    在页面中,根据自己的电脑选择正确版本,执行下载操作。

    在等待下载的过程中,我们需要开启Windows中"适用于Windows的Linux子系统"这项功能。

这是因为Docker需要Linux中的容器封装技术,所以需要系统中内置的Linux主机来创建镜像、运行容器。

在安装过程中非常简单只需要点击"下一步"即可。如果需要指定安装路径,则需要使用cmd中的cd命令加载到安装包所在目录中,然后运行以下命令。

bash 复制代码
# 先进入到安装包所在目录中
cd <安装包目录>
# 执行这行命令
start /w "" "Docker Installer.exe" install --installation-dir=<指定的路径>

如果显示"拒绝访问",或者出现了奇怪的问题,可以以管理员身份运行cmd,然后重新按照上文中的顺序执行命令。

安装完成以后,我们点开桌面上软件的图标,进入到软件的主界面中

**接下来使用Docker的时候,我们需要保证这个软件是启动的。**验证Docker安装状态的话则需要在powershell或者cmd窗口中输入命令

bash 复制代码
docker --version 

如果显示了Docker的版本号,则表示安装与环境配置成功了。

这样,Windows中Docker环境就配置完成了。

Linux

Linux中的环境配置比Windows中的更简单。

首先,我们需要在浏览器中访问这个网页get.docker.com

然后按照其中的指示,运行命令1与命令4

也就是这两个命令

bash 复制代码
# 获取Docker
curl -fsSL https://get.docker.com -o install-docker.sh
# 安装Docker
sudo sh install-docker.sh

等待一分钟左右就会安装完成。

如果指定第一条命令报错的话,可以先执行下面的命令:

bash 复制代码
sudo apt install curl

然后重新执行上面的第一条命令。
*

Mac

Mac安装的过程与Windows中的类似,也需要在官网中根据自己的芯片类型下载对应的版本,然后直接安装即可。

在安装完成以后,打开软件,再调出控制台,同样输入以下命令验证安装状态

bash 复制代码
docker --version 

安装成功了Docker以后,我们就可以进行后续拉取、运行的操作了。

后面的操作主要在Windows中的powershell界面中演示,Linux、Mac中使用的命令与这里的命令相似,如果Linux中对应命令无法使用,则需要在命令最前面加上sudo即可。

bash 复制代码
sudo <运行的命令>

【拉取指定镜像💿】

在Docker中,拉取镜像的操作与git中拉取项目的操作相似,都需要使用到pull命令。

在保证Docker桌面端运行的情况下,使用以下格式命令就可以获取到指定的镜像了。

bash 复制代码
docker pull <指定镜像地址>

其中,指定的镜像地址是这样的(以Nginx做演示)

复制代码
docker.io/library/nginix:latest

地址被/分为了三个部分

名称 作用
docker.io 官方镜像地址,默认为官方镜像地址
library 命名空间,一般是用户名,默认为官方
nginix 镜像名称
latest 版本号,默认为最新

所以,这里拉取nginx镜像的命令可以简写为:

bash 复制代码
docker pull nginix

这样,Docker就会自动从官方的镜像中拉取nginix的最新镜像。

不过,在进行这一步的时候有可能会显示报错

复制代码
error during connect: Post "http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/v1.48/images/create?fromImage=nginx&tag=latest": open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.

这是因为电脑中的Docker服务没有启动,在Linux系统中,需要使用命令

bash 复制代码
sudo service docker start

来启动Docker服务,如果是Windows或者Mac系统,则启动桌面端软件即可。

还有一种报错是

复制代码
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

这表示因为网络的问题导致无法从官方镜像站拉取指定的镜像。

对于这种情况,则需要使用国内的镜像站来进行拉取操作,我们需要修改Docker的配置文件。

在Linux系统中,这个配置文件一般位于Docker安装目录中,名称为daemon.json文件。

使用vi编辑命令打开这里的文件,并将以下json代码粘贴到文件中。

json 复制代码
{
"registry-mirrors" : [
    "https://docker.m.daocloud.io", 
    "https://docker.1panel.live", 
    "https://hub.rat.dev"
  ]
}
  

退出编辑,然后使用以下命令重启Docker服务。

bash 复制代码
sudo service docker restart

重启了服务以后,重新拉取指定镜像。

在Windows与Mac中,则需要进入到Docker Desktop的设置界面中,来到Docker Engine页面中,先将输入框中的内容删除,然后将下文中的代码粘贴到输入框中。

json 复制代码
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors" : [
    "https://docker.m.daocloud.io", 
    "https://docker.1panel.live", 
    "https://hub.rat.dev"
  ]
}

然后点击右下角的Apply&Restart按钮,就可以成功应用我们的修改。

成功拉取镜像以后,我们就能在界面中看到镜像的下载情况了。

等下载完成以后,我们就能使用下面的命令来查看所有我们下载过的镜像。

bash 复制代码
docker images

在界面中会显示一个表格,其中显示的就是我们已经下载的镜像列表。

如果需要将指定的镜像删除的话,则需要需要使用如下命令模板

bash 复制代码
docker rmi <镜像名称>

删除成功以后,则会显示删除信息。

在pull命令中,还有很多的参数,例如--platform参数用于指定镜像运行的平台,不过这个参数一般来说不用特殊的指定,系统会自动为我们选择。

【通过镜像创建容器🪣】

在上文中我们对Docker的介绍中提到,我们可以通过下载的镜像创造出指定的容器。

如何创建容器呢?是通过Docker中的run指令来进行的。

bash 复制代码
docker run <指定镜像名称或者ID>

这样,就成功创建并启动了容器,容器的日志也会同步打印在指定的控制台中。

可以看到,在这个窗口中无法输入其他的命令了。这是因为该容器将该窗口阻塞了,无法输入新的命令。

我们需要再开一个窗口出来,然后使用以下命令来查看容器进程的运行状态。

bash 复制代码
docker ps

这里的psprocess status的缩写,用于查看进程的信息。

可以看到,显示出的信息中就有我们刚刚运行的容器。

其中含有多个重要的参数

参数 意义
CONTAINER_ID 容器的运行ID
IMAGE 容器来源的镜像
NAMES 容器的名称(随机分配)

无日志的Docker运行模式

上文中的演示中,我们看到日志已经填满了窗口,并且不能运行新的命令。如果我们不想窗口被日志占据的话,则需要使用参数-d

这里的-d意思是detach mode,表示分离模式,即日志和主窗口分离,这样日志就不会显示在窗口中,而是在后台记录。

bash 复制代码
docker run -d nginx

需要注意的是这里参数-d的位置,一定要在镜像名称的前面,否则会输出报错。

这样,在容器运行起来以后,就只会显示该容器的ID,而不会显示其日志的内容。

同样,这样启动的容器可以在Docker的进程管理中被找到。

可以看到,在进程管理器中显示的ID是来源于完整的ID的切片。

Docker中的端口映射

我们知道,Docker创建的容器与外界的宿主机是完全隔离的关系。也就是说,在正常的情况下,容器如虚拟机相似,其中的运行结果与修改不会影响到宿主机的状态。

不过有些程序,例如上文中下载的nginix,就需要通过特殊的端口来验证运行的状态。

使用run命令运行这里的nginix镜像,我们来看看本地的80端口是否可用。

复制代码
localhost:80

将上文中的链接粘贴到网址栏中,按下回车尝试访问。

可以看到,这里是无法访问到nginix的。

我们使用stop命令关闭这里的容器,并使用run命令重新启动容器。

bash 复制代码
# 关闭容器
docker stop <容器ID>
# 指定参数重启容器
docker run -p 80:80 -d <容器名称>

这里的-p参数就是为容器指定映射的端口,在冒号前后两个参数分别是

复制代码
<想要指定在宿主机中使用的端口号>:<容器中指定进程使用的端口号>

这里的p表示的就是port,意为端口。

因为nginix默认是使用80端口号,因此容器中指定进程使用的端口号就为80;为了保持统一,我们设置宿主机中的80端口映射容器中的端口80。

这样,我们就能进入到容器中的nginix中。

当然,如果喜欢的话,将容器的80端口映射到宿主机的79端口也是可以的,但是需要将启动命令改为

bash 复制代码
# 前面一个代表的是宿主机中的端口
docker run -p 79:80 -d <容器名称>

这样就将端口映射到了79端口上了(不过在edge浏览器中这个端口好像是无法访问的状态)。

不过在映射到其他端口上的时候,需要保证该端口上没有其他的服务在运行,否则可能会导致奇奇怪怪的错误。

Docker中的文件映射:绑定挂载

Docker与宿主机的隔离关系,不仅体现在端口、网络上面,显而易见还有文件方面的隔离。这代表着容器对文件的操作是无法映射到宿主机中的文件的。

但是,如果需要容器中文件永久化保存呢?那就需要使用容器的文件映射了。

在Docker中,文件映射使用参数-v来表示,意为volume,这里的使用格式与上文中端口的使用格式相似。

复制代码
-v <宿主机的格式>:<容器中的路径>

我们将上文中的格式代入到命令中

bash 复制代码
# nginix网页文件固定存储到路径/usr/share/nginx/html中
docker run -d -p 80:80 -v /d/html:/usr/share/nginx/html nginx 

执行了命令以后,我们发现网页无法使用了。

这是因为Docker在映射以后,nginix容器将尝试访问并读取映射以后的文件地址,也就是宿主机中的文件地址。

这是因为nginix的主界面需要访问index.html文件,但是在宿主机的映射文件夹中没有index.html文件,于是就会显示这样的报错。

这时候我们只需在宿主机的对应文件目录中创建一个index.html文件,这里的就会显示出对应的结果。

上图是我使用AI编写的一个用于测试请求的html文件,可以看到这里的映射是可用的。

如果我们关闭文件映射,重启这里的容器的话,网页则会变为原来的样子。

在编写宿主机映射路径的过程中,如果需要使用上文中的Linux风格的路径,则需要注意加上对应的盘符,如果不加上对应的盘符的话,则是在Docker虚拟机中创建对应的目录。

复制代码
# 加上了/d/则表示在D盘中自动创建一个名为html的文件夹
/d/html
# 不加上盘符则是在Docker虚拟机中自动创建对应文件夹
/html

Docker中的文件映射:命名卷

在上文中我们尝试将容器中的文件夹绑定到宿主机的特定文件夹中,指定容器使用对应文件夹中的内容。

Docker中,还有另一种映射文件的方式,那就是将文件以卷的形式保存。

在使用卷之前,我们需要创建一个卷出来,那就需要使用以下命令

bash 复制代码
docker volume create <卷名称>

运行以后,则会自动按照我们给定的一个卷名称创建一个自定义的卷。

命名卷与上文中讲到的绑定负载的区别就是,命名卷不用我们来管理容器的储存位置,这一切Docker都会为我们管理。

并且相对来说,使用命名卷可以让镜像可移植性变得更高,同时兼容多种系统,这样可以更好的适配生产环境。

在创建了自己的卷以后,我们可以通过以下命令来查看卷的列表和对应卷的详细信息。

bash 复制代码
# 查看卷的列表
docker volume list
# 查看对应卷的详细信息
docker volume inspect <对应卷名称>

将上文中命令执行以后,我们来看看这里的效果

在运行了查看卷的详细信息命令以后,其中会显示一个路径,这个路径是这个卷实际存储的位置。

并且新的命名卷中是没有文件的,是一个空文件夹。只有在命名卷被第一次使用的时候,Docker容器中映射的文件夹中的内容会自动同步到命名卷中。

但是这个卷的实际位置是在Docker的Linux虚拟机中,是无法在Windows中直接找到的。

接下来,就可以在创建容器的时候直接使用了。

bash 复制代码
# 将这里的路径直接替换为刚刚创建的卷
docker run -d -v -p 80:80 nginx_test:/usr/share/nginx/html nginx 

运行以后,我们通过另一个容器来访问一下命名卷,看看其中是否有内容。

这里笔者将使用Alpine这个轻量化Linux来查看一下其中的内容。(这里的Alpine也是一个镜像,需要读者自行下载)

bash 复制代码
# 我们将这里的命名卷挂载到虚拟机中的volume目录底下
docker run -it --rm -v nginx_test:/volumes alpine sh
# 访问这里的volume目录
cd volumes/

在显示的文件列表中我们可以看到一个非常熟悉的文件:index.html

同样,我们尝试将这里的index.html文件中的内容改为上文中index.html文件中的内容。

这里,我们就要使用到vim编辑器,使用命令让vim打开index.html

bash 复制代码
vi index.html

然后修改其中的内容为我们自己的测试界面。

使用以下命令保存并退出以后,我们来到浏览器中重新刷新一下就能看到我们自己的测试页面了。

复制代码
:wq

如果想要看到创建的所有的命名卷,则需要使用命令list来实现,具体的使用格式如下

bash 复制代码
docker volume list

这样,就会显示出所有存在的命名卷。

当然,这些命名卷都是允许删除的,也是使用rm命令来实现。

bash 复制代码
docker rm <指定命名卷名称>

在删除以后,卷中所有的内容都会消失,并无法恢复。

删除命名卷之前,我们需要删除使用该命名卷的容器,就算是该容器已经是停止状态,也会导致对应的命名卷无法被删除。

bash 复制代码
# 查看是否存在容器使用指定的命名卷
docker ps -a
# 再执行删除操作
docker rm <指定卷的名称>

run命令的其他参数

除了上文中常用的几种参数,接下来还会介绍几种便于容器的使用的参数。

  • --name:表示的是指定创建容器的名称

    在上文中的容器进程截图中,我们可以看到在显示的信息中包含了一个NAME字段。

    最后的NAME字段在默认的情况下是Docker随机使用几个单词拼接起来的,如果使用了--name参数的话,则会变为我们指定的那个参数。

    bash 复制代码
    docekr run -d -p 80:80 --name my_nginx nginx

    这样,就就可以成功创建出一个自定义名称的容器了。

    其实,这里名称的最大作用与容器的ID相同,我们可以通过这里的名称将容器停止或者删除。

    bash 复制代码
    # 停止容器
    docker stop my_nginx
    # 删除容器
    doker rm my_nginx

    可以看到,这里的效果与上文中使用ID删除的效果是相同的。

  • -e:传递全局变量

    在一些容器中,在使用的时候可能需要向其中传递必要的参数,否则该容器将无法运行。

    Docker中,传参主要是使用参数-e来进行,这里的e表示为environment(环境)。

    例如,数据库MongoDB在初始化的时候可以预设上root的账号和密码,这就需要使用-e参数来传递到容器中。

    bash 复制代码
    docker run -d -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=carro -e MONGO_INITDB_ROOT_PASSOWRD=123456 mongo

    启动成功以后,我们在另一台电脑上按照刚刚预设的账号和密码来尝试进入到容器中。

    bash 复制代码
    mongosh "https://<预设账号>:<预设密码>@<宿主机的IP地址>:<指定的端口号>"

    如果在这台电脑上成功进入到数据库中,这说明我们的环境配置是生效的。

  • -it:使用终端并允许用户提供输入

    我们可以将该命令拆解开来,理解为两个部分:

    部分 意义
    i(interactive) 交互性
    t(tty) 终端

    使用了该命令以后,本来无法交流的容器将会变成一个可交互的终端,我们就可以向其中输入测试命令了。

    为了表现出区别,我们这里分别演示一下不使用参数i与不使用参数t的情况。

    如果命令中只有-i参数,那么可以向终端中输入信息,但是不会显示终端中的任何反馈。

    如果命令中只有-t参数,那么只会显示终端的样式,但是终端不接受用户的输入。

    因此,这两个命令是组合使用的,即为参数-it

  • --rm:一次性使用

    如题,使用了该参数以后,容器退出以后,Docker就会自动删除对应的容器。

    一般来说,该命令主要与上文中的-it命令组合使用,达到临时调试的目的。

    上文中,我们查看nginx所使用的命名卷中的内容,就是使用了这种方法来启动了Alpine这个轻量化的Linux实现的。

    bash 复制代码
    docker run -it --rm alpine sh

    这样使用完了以后,就可以针对本次调试的情况来进行判断或者修正容器中的内容。

  • --restart:确定容器退出以后的计划

    我们可以将该参数视为一个计划重启的参数。

    也就是容器不管因为什么原因停止了以后,Docker将使用哪种计划来重启该容器。

    使用了该参数以后,我们还需要指定计划的执行形式,常用的形式主要是以下两种。

    形式 意义
    always 不管因为什么原因造成的停止,Docker都会尝试重启
    unless-stopped 除了手动停止的容器,其他情况下Docker都会尝试重启

    使用的格式与其他的命令相似,直接接在后面就行

    bash 复制代码
    docker run -d -p 80:80 --restart always nginx

    根据上文中的设置,就算是我们尝试手动停止该容器,容器也会自动重启。如果一定需要停止该容器,只能将该容器强制删除。

    强制删除则需要使用以下命令

    bash 复制代码
    docker rm -f nginx

【Docker容器操作🔩】

我们创建了容器以后,便可以在命令行中对其进行操作。

容器中操作的命令与Linux中的命令非常相似,所以我们只要将两者类比操作就行了。

ps:进程查看命令

我们查看Docker中容器的运行状态,是通过ps这个命令来完成的。

bash 复制代码
docker ps

该命令在上文中已经详细演示过,接下来我们主要了解的是它的一个参数:-a

bash 复制代码
docker ps -a 

这里的a表示为all,表示显示所有容器的信息,包括不运行和运行的容器。而在一般情况下,显示的都是正在运行的容器的信息。

stop/start:容器停止与启动命令

容器的停止命令在上文中也演示过,也就是stop命令。

bash 复制代码
docker stop <容器的名称或者容器的ID>

如果需要强行停止容器的话,加上-f参数即可。

停止的命令是stop,那么启动的命令就是start了,我们可以使用以下命令来启动指定的容器,相对于使用run命令重新创建一个容器来说,节省了容器的使用空间,因为使用的是已经创建的容器。

bash 复制代码
docker start <容器的名称或者容器的ID>

并且,使用start启动容器的时候不用重新写入参数,Docker会自动保存我们创建容器的时候使用的参数,在启动容器的时候,会按照原有的参数自动启动。

exec:重新进入交互界面

上文中,我们重启了一个Alpine的容器,按理来说我们会直接进入到Alpineshell中,但是从上文中来看却不是这样的。那么我们该如何重新进入到shell中呢?

如果需要重新进入到容器的交互界面中,则需要满足这个重要的条件:容器是存在的并且是开启状态。

那么,我们直接使用命令来查看容器的运行状态:

bash 复制代码
# docker ps命令只会显示正在运行的容器
docker ps 
# 如果容器不在运行,那么先要知道容器的ID或者容器的名称,这就需要使用到-a参数
docker ps -a 
# 查找到了对应的容器的ID或名称以后,我们需要将该容器启动起来
docker start <容器的名称或者容器的ID>

最后,再使用命令docker ps命令来验证容器是否启动成功了,启动成功以后,我们就可以用exec命令重新进入到容器中。

bash 复制代码
docker exec <容器的ID或者名称>

这样就可以重新加入到容器中了。笔者这里使用Alpine来演示一下

值得注意的是,在重启命令以后,这里使用了-it参数。

这是因为这里需要使用到交互式终端 。这里的Alpine是一个Linux系统,需要我们向容器中输入命令才能正常使用。

如果需要在指定的容器中输入多个命令的话,那么就需要使用参数-it,让系统分配一个伪终端,便于查看命令的执行结果;如果只是需要执行一行命令的话,则可以不使用-it参数。

bash 复制代码
# 查看容器中的目录
docker exec <容器名称或者ID> ls 

这样就会输出当前目录中所有的文件和文件夹,并且该命令执行之后自动退出该容器。

但是正如上文中所述,该命令不能同时执行多个命令,它只会执行第一个命令。

exec命令的其他妙用

当然,并不是只有Alpine才具有交互式命令窗口,而是所有的容器都包含这个功能。

笔者这里使用nginx来进行演示:

bash 复制代码
# 先创建一个实验容器
docker run -d -p 80:80 --rm --name my_nginx nginx sh
# 同样使用上文中的格式命令进入到容器中
docker exec -it my_nginx sh 

这样,我们就进入到nginx容器的系统交互界面中。在这个交互界面的系统中,我们可以访问到该容器中的任何文件,包括界面中的配置文件。

但是,这里却无法使用vi编辑器打开该文件。

这是因为,Docker中使用的都是极简的Linux系统,其中只包含了系统的基础功能,其他的功能都是无法使用的。所以在使用这里的功能之前,我们需要安装vim工具。

在安装之前,我们需要查看这里的Linux型号,不同的Linux对应这不同的下载工具。

bash 复制代码
# Linux版本一般会记录在该文件中。
cat /etc/os-release

这样,里面就会显示出该镜像中使用的Linux型号和版本。

笔者这里的Linux型号是Debian,需要使用apt命令来进行安装操作,其他的Linux发行版中使用的安装命令如下表

发行版 包管理命令 安装示例 更新包列表
Debian/Ubuntu apt apt install vim apt update
Alpine apk apk add vim apk update
CentOS/RHEL 7 yum yum install vim yum check-update
CentOS/RHEL 8+ dnf dnf install vim dnf check-update
Fedora dnf dnf install vim dnf check-update
Arch Linux pacman pacman -S vim pacman -Sy
openSUSE zypper zypper install vim zypper refresh

在使用安装工具之前,我们需要对其进行更新操作,只要执行上文中对应的"更新包命令"字段中的命令即可。笔者的Linux发行版本是的Debian,需要执行下文中的命令来更新。

bash 复制代码
apt update 

更新完成以后,我们再安装vim编辑器,只需要执行上文中对应的"安装示例"中的命令即可。同样,笔者使用的安装命令

bash 复制代码
apt install vim 

等待安装完成以后,我们在命令中输入vim,如果进入了vim主界面中,则表示安装成功了。

接下来,我们修改一下nginx容器中index.html文件中的内容,看看在对应的网页中是否会生效。

bash 复制代码
vi usr/share/nginx/html/index.html 

将我们的测试内容粘贴进去,保存退出以后刷新nginx的测试界面。

这样,我们就成功应用了我们的更改。

inspect:容器参数查看

如果我们忘记了容器在创建时设置的参数,那么我们可以通过inspect命令来查看容器使用的参数。

bash 复制代码
docker inspext <容器的名称或者ID>

命令执行以后,将会显示容器的具体状态。

我们先创建一个用于测试的容器出来。

bash 复制代码
# 创建用于实验的容器
docker run -d --rm -v /d/html:/usr/share/nginx/html -p 80:80 --name test_nginx nginx
# 使用inspect命令查看其中的参数
docker inspect test_nginx

然后,我们就能看到这些参数

上面的参数多少是有点复杂了,所以我们只要将其全部复制下来,然后粘贴给AI,让他帮我们分析就行了。

接下来,直接询问AI相关的问题就行了。

create:创建容器命令

在上文中我们提到了一个在Docker中创建容器的命令:run,还有另一种命令的功能与这个命令相似,不过相对run命令来说,它不会立即启动。

它就是create命令。

bash 复制代码
docker create <定义参数> <镜像名称>

我们来看看它在命令行中的执行效果

在运行了命令以后,容器并不是运行状态,而是保持在"被创建"的状态,需要我们使用start命令才可以启动容器。

logs:容器日志查看器

还记得在我们第一次启动nginx的时候,终端中显示出了很多日志的内容。

我们使用了参数-d以后,终端中就不会显示日志了。如果我们想要查看这里的日志呢?那就需要使用logs命令。

bash 复制代码
docker logs <容器的ID或者名称>

运行了命令以后,我们就可以看到从容器创建开始的所有日志。

如果我们想要终端中随时更新最新的日志,那么就需要使用到参数-f,表示为follow(跟随)

那么接下来容器中出现了新的日志信息,会实时显示在终端中。

这样就实现了日志的跟踪功能。

【Docker创建自己的镜像并推送💿】

在上文中,我们学习了如何通过镜像创建容器。接下来,我们来看看镜像是如何创建的。

在创建镜像之前,我们需要先明白镜像中的主要构成。

  • Dockerfile:镜像的配置文件。
  • 项目的目录:其中存放着项目的文件

其中,Dockerfile主要是存放着镜像的配置方法, 这些方法会被Docker自动读取。

Dockerfile文件构建方法

Dockerfile文件的编写方法十分简单,主要是以下面的几个命令组成的。

  • FROM

    表示该镜像是通过什么镜像改装而来,这里的镜像一般是由我们镜像的环境决定的。

    例如需要镜像中包含Python环境的话,那么就需要我们选择一个Python的镜像版本填写上去,关于Python的具体镜像版本我们可以通过DockerHub来查看。

    dockerfile 复制代码
    FROM python:Alpine 

    这样,就确定了镜像的来源

  • WORKDIR

    这个命令类似于命令行中的cd命令,表示进入到一个指定的文件夹中,该命令后面的所有命令都会在进入的文件夹中进行。

    如下文中的这样的命令

    dockerfile 复制代码
    WORKDIR /app

    这样就进入到了目录名称为app的文件夹中,如果该文件夹不存在的话,Docker会自动为其创建一个。

  • COPY

    用于将指定目录中的文件复制到镜像中的指定目录中。我们在这里举一个例子

    dockerfile 复制代码
    COPY . .

    上文中的命令是将当前目录中的文件复制到镜像的工作目录中,镜像的工作目录位置就是由上文中的WORKDIR命令决定的。

    其中,第一个点表示的是宿主机当前香型目录,第二个点指的是镜像中的工作目录。

  • RUN

    该命令用于安装镜像中的依赖,或者在镜像启动前运行指定的系统命令。

    就像是一个基于Python开发的镜像,在启动前需要根据requirements.txt文件中的内容安装程序运行依赖。

    bash 复制代码
    RUN pip install -r requirements.txt

    这样,镜像在创建容器的时候,其中的运行环境就会自动进行配置。

  • CMD

    用于表示程序如何开始执行,在启动容器的时候会自动在系统中执行这个语句。

    dockerfile 复制代码
    CMD ["python3", "main.py"]

    正如上文中的这样,里面包含多个参数,各个参数中禁止含有空格,并且使用Python列表的格式写在文件中。

    这里的参数,就是各个命令中去除空格以后的各个部分。

    在正常的终端中,我们是这样启动主程序的:

    bash 复制代码
    python3 main.py

    那么,去除了命令行、将各个部分包装成Python的元素,然后放入到列表中。

    dockerfile 复制代码
    CMD ["python3", "main.py"]
  • ENTRYPOINT

    该命令的作用与上文中的CMD相同,不过相对于上文的命令,ENTRYPOINT命令的优先级更高。

    为了容器的调试便利性,一般来说都是使用上文中的CMD命令。

除了以上最常用的命令,这里对所有常用的命令进行了汇总

指令 用途 示例 说明
FROM 指定基础镜像 FROM ubuntu:20.04 FROM python:3.9-alpine 必须是 Dockerfile 的第一条指令(ARG 除外)
LABEL 添加元数据标签 LABEL version="1.0" LABEL maintainer="your@email.com" 用于记录镜像的版本、维护者等信息
ARG 定义构建时的变量 ARG APP_VERSION=1.0 ARG DEBIAN_FRONTEND=noninteractive 仅在构建过程中有效,不会保留在镜像中
ENV 设置环境变量 ENV NODE_ENV=production ENV PATH=/app:$PATH 在容器运行时持续有效
WORKDIR 设置工作目录 WORKDIR /app WORKDIR /usr/src/app 相当于 cd,若目录不存在会自动创建
COPY 复制文件/目录到镜像 COPY . . COPY package.json ./ COPY --chown=user:group src dest 源路径是相对于构建上下文
ADD 复制并解压/下载 ADD app.tar.gz /app ADD https://example.com/file /tmp/ 功能比 COPY 多,但推荐优先使用 COPY
RUN 执行命令 RUN apt-get update && apt-get install -y nginx RUN pip install -r requirements.txt 每 RUN 一层都会生成新的镜像层
EXPOSE 声明端口 EXPOSE 80 EXPOSE 3000/tcp 仅作声明,实际映射需在 docker run -p 中指定
VOLUME 创建挂载点 VOLUME ["/data", "/logs"] 用于持久化数据,推荐使用命名卷或绑定挂载
USER 切换用户 USER node USER 1000 避免以 root 用户运行容器,提升安全性
CMD 容器启动命令 CMD ["python", "app.py"] CMD nginx -g 'daemon off;' 一个 Dockerfile 只能有一个 CMD,会被 docker run 覆盖
ENTRYPOINT 入口点 ENTRYPOINT ["python"] CMD ["app.py"] 与 CMD 配合使用,CMD 作为参数传递给 ENTRYPOINT
HEALTHCHECK 健康检查 HEALTHCHECK --interval=30s CMD curl -f http://localhost/ 定期检查容器健康状态
SHELL 指定 Shell SHELL ["/bin/bash", "-c"] 更改 RUN、CMD、ENTRYPOINT 使用的 Shell
ONBUILD 触发器 ONBUILD COPY . /app 在当前镜像被作为基础镜像时执行

Dockerfile创建实战

接下来,我们来实践一下上文中的理论知识:使用Dockerfile创建容器。

我们将构建一个初始界面就自定义界面的nginx容器,这也就意味着我们需要替换usr/share/nginx/html路径中的index.html文件为自己的文件。

dockerfile 复制代码
FROM nginx:alpine 

WORKDIR /usr/share/nginx

COPY . ./html

EXPOSE 80 

# 这个命令用于运行nginx,是固定命令。
CMD ["nginx", "-g", "daemon off;"]

我们在当前的工作目录中放入自定义的index.html文件,文件中的测试内容可以自己让AI生成。

Dockerfile这个容器的配置文件编写完成以后,我们就可以使用build命令创建一个自己的容器了。

bash 复制代码
# -t参数用于自定义一个名称,最后面的点表示在当前目录中创建。
docker build -t nginx_test .

接下来,Docker会自己创建对应的镜像。

等待这里的程序跑完了以后,我们刚刚创建的镜像就可以在镜像列表中找到了。

接下来,我们使用该镜像创建一个容器。为了与之前使用的nginx区别开来,我们使这里的容器运行在8080端口上。

然后在浏览器中访问8080端口,看看呈现的效果:

这里显示了新的界面,这说明我们自定义的镜像创建成功了。

Docker推送镜像到DockerHub

在上文中,我们成功创建了自己的镜像,接下来我们将尝试将其推送到DockerHub上面。

再推送之前,我们需要满足以下两个条件:

  1. 网页端的DockerHub已经登录了自己的账号
  2. 在终端中登录自己的Docker账户
  3. Docker镜像中需要包含自己的Docker用户名

第一个条件非常好满足,只需要访问DockerHub的官网,然后点击sign in按钮登录即可。如果有读者还没有自己的账号,则需要点击sign up按钮创建一个自己的账号。

接下来,在终端中输入命令

bash 复制代码
docker login 

这样,终端就会显示一个验证码和一个用于登录验证的网站,打开网站以后将验证码填写进去以后点击输入框下方的按钮,看到终端中显示login succeeded则表示登录成功。

如果在这里显示认证失败的话,则需要挂上魔法才可以认证成功。

在认证完成以后,我们要看看自己的镜像名称是否符合以下格式:

复制代码
<Docker中的用户名>/<镜像名称>

如果不是的话,则需要重新打包一个镜像

bash 复制代码
docker build -t <Docker中的用户名>/<镜像名称> .

打包完成以后,就可以使用push命令将镜像推送上去了。

bash 复制代码
docker push <Docker中的用户名>/<镜像名称>

这里一定要注意的是,这里推送的镜像名称中一定要带上个人的用户名,这样才能推送成功。

Docker网络🕸】

Docker中,我们可以使用网络将各个容器的通讯连接起来或者隔离开来。

Docker中默认使用的网络模式是桥接模式,除了这种模式还有其他两种模式,分别是host模式和none模式。

  • host模式:将容器中的网络连接到宿主机的端口中,如果访问宿主机的对应端口则会自动转到容器中。
  • none模式:不允许容器连接网络,其他的容器也无法访问该容器。

我们还可以自己创建一个独立的网络, 我们自己创建的网络会显示在Docker的网络列表中。

bash 复制代码
# 创建自己网络的命令
docker network create <网络的名称>

终端中显示了网络的ID,这样就表示我们自定义的网络已经创建成功了。

接下来,我们可以使用list命令来查看Docker中已经创建的网络。

bash 复制代码
docker network list

执行以后,在终端中就会显示我们已经创建的网络名称和ID。

其中的bridge、host和none这三个网络是自带的,并且无法被删除,算是Docker中的基础网络。

如果我们想要将指定的容器加入到指定的网络中,那么就需要使用--network参数。

复制代码
--network <网络的名称>

例如,我们想要将nginx加入到my_network网络中。

bash 复制代码
docker run -d -p 80:80 --network my_network nginx

得益于Docker中自带的DNS机制,在同一个网络中的容器可以通过容器的名称相互访问。

我们这里启动两个在相同网络中的容器,然后使用ping命令来看看两者能不能相互连接到。

bash 复制代码
# 这里我们再启动一个Alpine容器,用于测试容器的连接
docker run -it --network my_network --name my_alpine alpine

然后,我们来看看终端中输出的内容

可以验证容器在同一网络中是可以相互通信的。

同样,我们可以使用rm命令删除这里的网络。

bash 复制代码
docker network rm <网络名称或者网络ID>

这样,我们就可以将自己创建的网络成功删除了。

Docker集中管理:Docker-Compose🐙】

在实际的项目开发中,项目的前端、后端和数据库都是分开部署的。

如果将这里的前端、后端和数据库都放在一个镜像中的话,如果其中一个部分出了问题的话,则会导致整个生产环境崩溃。

所以一般来说,前端、终端和后端都会被单独打包成镜像,然后使用下文中介绍的Docker-Compose,也就是容器编排技术来进行统一的启动。

初识yaml文件

容器编排技术主要通过yaml文件来进行管理。

我们来对比一下yaml文件中的内容和使用run命令启动的区别。

  • 使用run命令启动

    bash 复制代码
    # 启动nginx的命令
    docker run -d -p 80:80 -v nginx_test:/usr/share/nginx/html --name=my_nginx nginx 
    # 启动Alpine的命令
    docker run -it -v nginx_test:/volumes --name my_alpine alpine sh 
  • 使用yaml实现相同的功能

    yaml 复制代码
    services:
      my_alpine:
        image: alpine:latest
        volumes:
          - nginx_test:/volumes
        stdin_open: true   # 相当于 -i 参数
        tty: true          # 相当于 -t 参数
        command: sh        # 覆盖默认命令
        restart: unless-stopped
    
      my_nginx:
        image: nginx:latest
        volumes:
          - nginx_test:/usr/share/nginx/html
        ports:
          - "80:80"
        restart: unless-stopped
    
    volumes:
      nginx_test:
        driver: local

但是现在AI时代,这里的yaml文件同样不用我们自己编写,可以将自己的命令复制下来,让AI编写等价的yaml文件。

在使用AI编写前,至少需要知道一些yaml文件中的语法和常用的命令:

Docker Compose YAML 指令 作用 对应的 Docker Run 命令 说明与示例
image 指定使用的镜像 docker run <镜像> 定义容器基于哪个镜像创建 image: nginx:alpine
container_name 指定容器名称 docker run --name 为容器设置名称 container_name: my_nginx
ports 端口映射 docker run -p 主机端口:容器端口映射 ports: ["80:80", "443:443"]
volumes 数据卷/目录映射 docker run -v 主机路径:容器路径映射 volumes: - ./data:/app
environment 环境变量 docker run -e 设置容器环境变量 environment: - VAR=value
tty 分配伪终端 docker run -t 分配终端设备 tty: true
stdin_open 保持标准输入打开 docker run -i 允许交互式输入 stdin_open: true
restart 重启策略 docker run --restart 容器退出时重启策略 restart: always
depends_on 服务依赖 无直接对应(手动控制) 确保服务启动顺序 depends_on: - db

还有一些是相对于run命令,yaml文件中特有的命令

Docker Compose YAML 指令 作用 说明
version Compose文件版本 必须放在文件开头 version: '3.8'
services 服务定义区块 定义多个服务的容器
build 构建镜像 指定Dockerfile路径构建镜像 build: context: . dockerfile: Dockerfile
profiles 配置文件 定义服务配置文件 profiles: ["dev", "debug"]
deploy 部署配置 用于Swarm模式(资源限制、副本等)

运行yaml文件

我们通过compose up命令来运行yaml文件。

bash 复制代码
docker compose up 

运行了上文中的命令以后,Docker会自动寻找目前的工作目录底下一个名为docker-compose.yaml的文件。如果无法找到则是显示报错。

如果想要指定任意名字的yaml文件启动的话,则需要使用参数-f指定文件的目录。在指定启动文件的目录的时候,需要使用相对路径或者绝对路径。

bash 复制代码
docker compose -f <文件的目录> up

执行命令以后,则会按照文件中的内容启动Docker镜像。

当然,这些镜像创建出来的容器能在进程列表中看到

如果需要将这里的容器全部关闭的话,则需要使用到stop命令。

bash 复制代码
docker compose stop

使用这个命令,所有根据yaml文件生成的容器都会被停止。

同样,使用start命令可以将文件中指定的容器启动。

bash 复制代码
docker compose start 

这样,容器就被启动了

如果需要删除文件的话,使用down命令即可。

bash 复制代码
docker compose down 

命令运行了以后,所有根据yaml生成的容器都会被删除。

接下来,我们尝试一下从特定的文件启动。

bash 复制代码
docker compose -f test.yaml up

效果与上文中的执行效果是相同的。

【总结与进阶 🚀】

至此,我们已经完成了 Docker 从基础概念到实际应用的完整学习之旅。你不仅理解了 容器、镜像、仓库 三大核心概念,还亲手实践了:

  • 安装与配置 Docker 环境(Windows / Linux / Mac)
  • 拉取与管理 镜像,使用国内镜像加速
  • 创建与运行 容器,掌握端口映射、文件挂载、环境变量等关键参数
  • 操作与管理 容器生命周期(启动、停止、进入、查看日志等)
  • 构建与推送 自己的镜像,编写 Dockerfile
  • 配置网络 与多容器通信
  • 使用 Docker Compose 编排多服务应用

Docker 的价值远不止于"环境统一"。它是现代 云原生、微服务、CI/CD 架构的基石,是每一位开发者和运维人员都应掌握的核心技能。

相关推荐
我送炭你添花2 小时前
树莓派 3B+ 部署 TR-069 ACS(自动配置服务器)GenieACS 实录
运维·服务器·网络协议
小明_GLC2 小时前
关于租用阿里云服务器拉取Docker镜像的问题
docker
扫地生大鹏2 小时前
阿里云大模型服务器安装SNMP包启发
运维·服务器
今晚打佬虎2 小时前
精准阻断 Docker 容器映射端口:流量路径诊断与 iptables 配置
运维·docker·容器
那年一路北2 小时前
基于 Maven + Docker 的 WebApp 打包与部署
docker·maven·web app
honsor2 小时前
机房/档案室专用以太网温湿度传感器:智能监控赋能环境安全
运维·网络·物联网·安全
yuezhilangniao3 小时前
K8s优化-大规模集群优化-大规模K8S优化-性能优化速查表-优化顺序-先阻塞瓶颈再性能瓶颈
容器·性能优化·kubernetes
晚风吹长发3 小时前
初步了解Linux中的信号捕捉
linux·运维·服务器·c++·算法·进程·x信号
阡陌..3 小时前
Linux下用docker调用pytorch-无法检测到cuda问题
linux·pytorch·docker