Docker Practice

这是一篇记录如何练习 Docker 操作的博客,我将先安装 docker,并且从 dockerhub 中拉取镜像并且运行。随后会介绍一些 Docker 指令。接着我会使用镜像创建容器应用,并且解释各个参数。最后我将从 Dockerfile 创建一个 docker 镜像并试着上传。

环境:CentOS 8.3,4 核 8G 云主机

Docker 安装

按照网站 Install Docker Engine on CentOS | Docker Documentation 的指引,我们需要先安装 docker:

首先,将机器上面的旧版本移除

1
2
3
4
5
6
7
8
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

随后我们安装 yum-utils 并且配置 manager,即从哪个 repo 安装 docker。这是官网最推荐的做法。

1
2
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装最新版本的 docker:

1
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

注:我这边安装出现了一些问题,加上 --allowerasing 再运行就没有问题了

安装过程中,要求我验证 fingerprint,其提供的是 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35 与官网上的相同,通过。

安装完成后,试着启动 docker 服务:

1
sudo systemctl start docker

我们可以通过运行 hello-world 镜像来验证 docker 是否顺利安装

1
sudo docker run hello-world

正常情况下,会打印出如下提示信息:

1
2
3
4
5
6
7
8
9
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
719385e32844: Pull complete
Digest: sha256:fc6cf906cbfa013e80938cdf0bb199fbdbb86d6e3e013783e5a766f50f5dbce0
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
... (此处表示一些不必要的信息已经被省略)

拉取镜像

我们可以拉取 busybox 镜像:

1
docker pull busybox

随后我们可以通过 docker images 查看设备上已经存在的镜像

1
2
3
4
5
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 8135583d97fe 2 weeks ago 4.86MB
hello-world latest 9c7a54a9a43c 4 weeks ago 13.3kB

可以看到,我们现在的镜像不仅包括 busybox 还有 hello-world, 也就是我们之前 run 的第一个容器应用。因为如果要运行一个容器应用,需要先将镜像拉取到本地,所以输入 docker images 显示本地镜像的时候也打印出来了 hello-world.

我们尝试着运行 busybox, 输入命令

1
docker run busybox

发现什么也没有输出,但是这并不是你做错了什么,也不是 bug。docker run 命令在将 image 镜像文件加载到生成容器应用的时候,会运行其中的 command。但是 busybox 中并没有任何 command,所以我们需要加入自定义的 command。

加上我们自己的 command 再试一次:

1
2
# docker run busybox echo "hello from busybox"
hello from busybox

辨析:镜像和容器的区别 镜像在被拉取下来没有运行的时候是镜像,运行了之后就变成了一个容器应用。

常用的 Docker 指令

以下是一些常用的 docker 指令:

1. docker ps

docker ps 命令可以查看当前正在运行的所有容器的状态,包括 CONTAINER IDIMAGECOMMANDCREATE (创建时间)STATUS (容器状态)

我们可以通过输入 docker ps 来查看目前有多少容器正在运行

1
2
 docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

发现控制台输出了一个空的列表,说明目前没有容器正在运行。如果我们需要查看所有容器无论是否在运行,那就输入 docker ps -a

1
2
3
4
5
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c46095ea7729 busybox "echo 'hello from bu…" 8 minutes ago Exited (0) 8 minutes ago beautiful_lalande
f6184adb4bf1 busybox "sh" 11 minutes ago Exited (0) 11 minutes ago focused_leakey
770f95105bfb hello-world "/hello" 23 minutes ago Exited (0) 23 minutes ago condescending_wiles

2. docker run -it

docker run -it 可以在我们创建 container 的同时,以交互式的形式获取到 container shell 的控制权。我们可以在 **docker run **命令中使用 –name custom_name 来指定 container 的名称,若不指定,docker 会为我们随机生成一个名字

我们可以通过 run -it 命令来创建一个 busybox container, 并且在其中运行几个 linux 命令。因为容器本身提供了一整套环境,这个环境是可以独立于宿主机的环境的,但是又构建在宿主机的操作系统之上,所以容器中实际上也运行着一个轻量级的操作系统。

1
2
3
4
5
6
7
8
9
10
# docker run -it busybox
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
/ # echo "hello busybox"
hello busybox
/ # uptime
06:07:02 up 1:10, 0 users, load average: 0.00, 0.00, 0.00
/ # cd home && pwd
/home
/home # exit

3. docker rm

docker rm -args 可以删除不在运行的 containerargs 可以是 container name/id (可以不写完整,但必须保证唯一),如果有做过 git commit 管理的话应该会有触类旁通的感受

我们删除两个容器:

1
2
3
# docker rm c460 f618
c460
f618

当然 id 也可以写全,一般来说写前四位就可以了

接下来使用 docker ps -a 命令来检查一下吧!

从镜像部署应用

在我们熟悉了 docker 的基本命令之后,我们可以从镜像部署一些简单的应用。docker 与虚拟机的不同之处在于,docker hub 提供了丰富的镜像,通过自由组合,可以发挥非常强大的作用。

我们先 git clone 一下 docker 官方提供的 getting-start 仓库,随后我们会编辑 Dockerfile 文件,定义拉取哪个镜像,并且通过 Dockerfile 定义所需要安装的相关依赖、通过什么安装、如何暴露端口。然后,我们会命名我们新构建的镜像,我们会通过这个新命名的镜像启动容器。

首先,我们先 git clone 相关仓库

1
git clone https://github.com/docker/getting-started.git

随后我们 cd 到 getting-start/app 目录下

1
cd getting-start/app

创建一个新的空文件 Dockerfile

1
touch Dockerfile

编辑 Dockerfile, 填写如下内容:

1
2
3
4
5
6
7
8
# syntax=docker/dockerfile:1

FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000

我们可以看到 dockerfile 中有很多语句,我在这里解释一下:

FROM node:18-alpine 说明我们的项目基于 node:18-alpine 镜像,然而我们本地没有,所以我们需要先拉取它。

RUN yarn install --production 说明我们需要通过 yarn 安装应用程序的依赖。

CMD ["node", "src/index.js"] 说明,当我们在从镜像创建容器的时候,默认的 cmd 指令是什么。

EXPOSE 3000 说明容器应用会开放 3000 端口。

以下是更为具体的命令和对应意义:

FROM 指定容器来自的镜像
RUN 容器中运行 shell 命令
ADD 将本地文件传送到容器指定位置
WORKDIR 将容器中某个目录设置为工作目录(当前目录)
EXPOSE 将容器中某个端口暴露出来(如上述 flask 工作在 5000 端口,将其暴露出来)
CMD 容器启动自动执行的 shell 命令
LABEL 设置一些额外的信息

在编写完成 dockerfile 之后,我们通过运行命令进行构建 docker 镜像:

1
docker build -t getting-started .

其中 -t 参数表示 tag,后面所跟随的字符串就是我们对于这个镜像的命名。最后的 . 表示在当前目录下构建 docker image。

在构建完之后,我们就可以通过镜像启动容器了,通过以下命令,将容器的 3000 端口映射到云主机的 3000 端口运行。其中 -d 命令代表 run in detached mode,即后台运行。 -p 命令代表 port, 建立端口映射。getting-started 就是我们之前命名的镜像名称。

1
docker run -dp 3000:3000 getting-started

以下是更加具体的参数以及解释:

-d 将 container 置于后台运行
-p local_port:container_port 将 container 的某个端口映射到本地
-P 将 container 所有正在监听的端口全部映射到本地的随机端口
-v local_path:contatiner_path 将本地的 local_path 文件夹映射到 container 的 container_path 文件夹并保持同步

关于-v参数的说明,当你使用到-v 参数时,如

1
docker run -d -v /home/data:/var/data --name test ubuntu

那么相当于你将本地的/home/data目录映射到container的/var/data目录,container的/var/data目录会和你的本地目录保持同步,同时,若/var/data目录不存在,docker会自动创建,反之,目录中的内容会被全部覆盖掉(和本地的/home/data保持同步)

上传 Docker 镜像到 dockerhub

登录 https://hub.docker.com/ 随后在导航栏的 Repositories 点击,找到 Create Repository,给你的镜像仓库命名,随便添加 description,可见范围设置为 public。

在你的终端输入命令

1
docker login -u YOUR-USER-NAME

进行登录,此处应该填写你 docker 的用户名,如果没有用户名,需要先注册。

注册成功之后,输入命令登录,随后会提示输入密码,输入。

随后使用 docker tag 命令给镜像赋值一个新的标签,同时此处的 YOUR-USER-NAME 也更换成用户名

1
docker tag getting-started YOUR-USER-NAME/getting-started

在赋值标签之后,使用命令

1
docker push YOUR-USER-NAME/getting-started

即可上传自己的镜像到 dockerhub.