Docker入门教程:从基本概念到实践操作
Docker入门教程:从基本概念到实践操作
Docker 是目前非常流行的容器化技术,可以帮助开发者轻松地打包、部署和运行应用程序。本文将从Docker的基本概念入手,通过具体的操作示例,帮助读者掌握Docker的基本使用方法。
Docker 安装
其他操作系统的安装方法可以在Docker官网找到,这里就不详细介绍了。需要注意的是,本文的所有示例都是在Ubuntu系统上完成的。
安装完成后,如果想要让普通用户也能使用docker命令,可以将当前用户添加到docker组中:
sudo usermod -aG docker your-user
请将your-user
替换为你的用户名,并在执行完成后重新登录以使更改生效。
要检查Docker是否安装成功,可以使用以下命令查看版本信息:
docker --version
或者执行以下两个命令进行测试:
docker version
docker info
Docker 基本组成
Docker的主要组成部分包括:
- image:这是一个只读模板,用于创建container。可以将其类比为面向对象编程中的类(class)。
- container:这是Docker的核心组件,一个独立、隔离的运行环境,包含了执行应用程序所需的所有组件。
- Docker registry:类似于GitHub,用于存储和分发images。公开的registry如Docker Hub,也可以创建私有registry。
Docker 指令:启动容器
在正确安装Docker后,可以使用以下指令启动一个容器:
docker container run -it node:20 /bin/bash
解释一下这个命令的各个部分:
docker container run
:启动一个新的容器。-i
或--interactive
:保持标准输入打开,以便与容器内的进程进行交互。-t
或--tty
:分配一个伪终端,并将其绑定到容器的标准输出。node:20
:用于启动容器的image名称。/bin/bash
:容器启动后要执行的命令。
执行完这行指令后,你会看到类似下图的画面:
其中4c9bee8fef4b
是容器ID,用于区分不同的容器实例。此时你已经进入了容器的环境中,在这里执行node -v
指令,会发现这个环境中已经安装了node,且版本是20.5.1。
在容器中执行ps aux
会看到PID为1的进程就是我们刚刚指定的/bin/bash
,这个信息非常重要,但我们在后面再详细讨论。
这里让我们做一个小测试:
- 在刚刚创建的容器中,创建一个文件,例如
touch AAA.txt
,建议完成后用ls
确认一下。 - 开启另外一个命令窗口,同样再执行一次
docker container run -it node:20 /bin/bash
,然后进入了一个容器,执行ls
看看,应该会看不到AAA.txt
这个文件。
这个测试说明了container是一个独立的、隔离的环境,即使是从同一个image启动的多个容器,它们之间也是相互隔离的。
要查看当前正在运行的容器,可以使用以下指令:
docker container ls
Docker Image
在更深入讨论容器的其他操作之前,我们先来看看node:20
这个image是从哪里来的。
当你第一次启动容器时,如果本地没有找到指定的image,Docker会自动从Docker Hub(默认的registry)拉取所需的image。例如,node:20
这个image就是从Docker Hub的node仓库拉取的。
Docker Hub上有各种各样的image,非常实用。例如,如果你想启动一个MySQL服务,但又不想直接安装在自己的电脑上,就可以从Docker Hub上拉取一个MySQL的image。建议尽量使用官方提供的image,以确保安全性和可靠性。
在启动容器之前,也可以先用以下指令把image拉取好:
docker image pull node:18
这里补充一下tag的概念。在Docker image的命名中,冒号(:
)前面的是名称,后面的是tag(image_name:tag_name
)。Tag通常用来表示版本信息,但也可以用于其他用途。如果没有指定tag,Docker会默认使用latest
作为tag。
要查看当前环境中已有的images,可以使用以下指令:
docker image ls
Image Layer
当我们从image启动一个container时,Docker会加载这个image作为只读层,并在其上添加一个可写层。所有在容器中的操作实际上都是在这个可写层中进行的。这就是为什么在第一个container中创建的AAA.txt
文件在第二个container中看不到的原因。
Docker提供了一个指令,可以将容器的状态保存为一个新的image:
docker container commit CONTAINER_ID [Repository:[Tag]]
例如:
docker container commit 4c9bee8fef4b node:20-updated
这个新image会在原有image的基础上再加上一层,包含对容器所做的修改。当使用这个新image创建新的container时,就会包含这些修改。
Docker的智能之处在于,它不会重复存储相同的layer,这样可以节省大量磁盘空间。这也是为什么image需要设计为只读的原因,只读可以实现共享而不会互相影响。
要查看image的历史记录,可以使用以下指令:
docker image history node:20
其他Docker生命周期指令
在node:20-updated
创建出来的container中执行exit
退出这个container,这时候如果执行docker container ls
会发现,只剩下两个container,而刚刚退出的那个container已经看不到了:
但是,如果加上-a
参数,就可以查看所有的container:
这是因为我们刚刚在启动container时,要它执行的命令是/bin/bash
(且PID为1),而当我们下了exit
指令时,是在退出这个bash,也就是退出了PID为1的这个process,既然主要的process已经停止执行了,这个container自然也就关闭了,我们之后再来讨论怎么让container持续执行。从这里也可以从Status这个栏位看到container已经退出多久。
这时候如果想要回到这个container里,可以通过docker container start CONTAINER_ID
来回到这个container里:
docker container start
只是重新启动这个container,执行后我们还是在本机中,如果要进入container中,可以通过exec
来进入container中,基本上这个指令常用的参数,例如-it
,跟docker container run
的时候差不多,我们就先不讨论了。
docker container exec -it CONTAINER_ID /bin/bash
这时候我们一样再执行exit,然后再下docker container ls
来检查,却会发现这个container还是活着的、跟刚刚不一样,我们通过docker container exec
再进去一次,这次在里面执行一下ps aux
:
这时候我们可以看到有两个/bin/bash
的process在运行,我们通过docker container exec
所执行的/bin/bash
其实是PID为26的这一个,所以当我们执行exit
时,退出的是这一个bash,而PID为1的这个/bin/bash
仍在执行中,所以这个container会持续存活。
跟docker container exec
有一个用起来很像的指令docker container attach CONTINER_ID
:
attach
这个指令一样会进入container中,用起来跟刚刚的docker container exec -it CONTAINER_ID
效果很像,但如果进去后执行ps aux
会发现只有一个/bin/bash
process。你应该可以猜到,如果这时候执行了exit
,会退出的是PID为1的/bin/bash
process,进而退出这个container。此时再通过docker container ls
或是docker container ls -a
来确认,会发现这个container已经关闭了。所以,虽然attach也能进入这个container中,但我自己很少用,以免一不小心把container给关掉…
移除image和container
如果电脑中存有太多的image,会占用硬盘空间,因此建议定期清除用不到的image。要移除image,可以使用以下指令:
docker image rm IMAGE_ID
但是,如果image正在被某个container使用,那么在移除container之前,你是无法删除这个image的。要移除container,可以使用以下指令:
docker container rm CONTAINER_ID
结语
本次记录了Docker的基本组件与操作,主要讨论了Docker container的执行与一些基本操作。也许在做过这些练习与测试之后,你心里会有一大堆疑问,有的话是很棒的事情,但如一开始所说的,我想先记录一些基本的操作,先会基本的运用,有点感觉后,然后再慢慢深入讨论。
下次仍旧会是基础篇,让我们来讨论怎么让container间可以彼此沟通,然后再来讨论我最喜欢的Dockerfile,这可是我个人认为docker可以如此成功的重要因素之一。
指令整理
这里把本文讨论过的指令都整理起来,方便大家复习与查找,另外也会列出旧版的指令对照,推荐使用新版的指令,虽然较长,但具有一致的结构,非常好学!
# 查看docker版本
docker --version
docker version
# 查看docker系统信息
docker info
# 从node:20 image启动一个docker container并开启输出入
docker container run -it node:20 /bin/bash
# 旧版指令
# docker run -it node:20 /bin/bash
# 查看目前正在运行中的container
docker container ls
# 旧版指令
# docker ps
# 查看全部的container,包括已经停止的。 (a -> all)
docker container ls -a
# 旧版指令
# docker ps -a
# 从DockerHub上拉下版本为18的node image
docker image pull node:18
# 旧版指令
# docker pull node:18
# 查看目前环境中的docker images
docker image ls
# 旧版指令
# docker images
# 用container id为4c9bee8fef4b的container
# 创建一个叫做node:20-updated的image
docker container commit 4c9bee8fef4b node:20-updated
# 旧版指令
# docker commit 4c9bee8fef4b node:20-updated
# 查看node:20这个image的历史
docker image history node:20
# 旧版指令
# docker history node:20
# 停止4c9bee8fef4b这个container
docker container stop 4c9bee8fef4b
# 旧版指令
# docker stop 4c9bee8fef4b
# 启动4c9bee8fef4b这个container
docker container start 4c9bee8fef4b
# 旧版指令
# docker start 4c9bee8fef4b
# 在4c9bee8fef4b这个container中执行/bin/bash这个命令,并且开启输出入
# 因为是执行/bin/bash又开启了输出入,所以就像是「进入」了这个container中
docker container exec -it 4c9bee8fef4b /bin/bash
# 旧版指令
# docker exec -it 4c9bee8fef4b /bin/bash
# 移除4c9bee8fef4b这个container
docker container rm 4c9bee8fef4b
# docker rm 4c9bee8fef4b
# 移除所有停止的containers
docker container prune -f
# 移除node:18这个image
# 移除image前要先移除用这个image启动的containers
docker image rm node:18
# 旧版指令
# docker rmi node:18