要使用 Docker 快速搭建一个 Ubuntu 20.04 的环境,并在该环境中安装 gcc
以及运行 uptime
命令,你可以按照以下步骤操作:
1. 安装 Docker
如果你尚未安装 Docker,可以使用以下步骤安装 Docker:
bash
# 更新软件包列表
sudo apt update
# 安装必要的软件包
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
# 添加 Docker 的官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加 Docker 的 APT 仓库
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 更新 APT 包索引,并安装 Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y
# 启动 Docker 并设置为开机启动
sudo systemctl start docker
sudo systemctl enable docker
2. 拉取 Ubuntu 20.04 Docker 镜像
使用 Docker 命令拉取 Ubuntu 20.04 的官方镜像:
bash
docker pull ubuntu:20.04
3. 创建并运行容器
使用以下命令创建并运行 Ubuntu 20.04 容器,并进入容器内部:
bash
docker run -it --name ubuntu20.04_container ubuntu:20.04 /bin/bash
这条命令会拉起一个 Ubuntu 20.04 的容器,并且将你直接带入容器的 shell 环境。
4. 在容器中安装 gcc
在容器内部,你可以通过以下命令安装 gcc
:
bash
apt update
apt install gcc -y
5. 执行 uptime
命令
在容器内部安装完 gcc
后,你可以运行 uptime
命令来查看系统的运行时间:
bash
uptime
6. 退出容器
完成操作后,可以通过以下命令退出容器:
bash
exit
7. 再次启动容器
如果你之后还想再次启动并进入这个容器,可以使用以下命令:
bash
docker start -i ubuntu20.04_container
总结
通过以上步骤,你就成功在 Docker 中搭建了一个 Ubuntu 20.04 的环境,并在其中安装了 gcc
以及运行了 uptime
命令。这种方法对于快速测试和开发非常有效。
当你在 Docker 容器中基于 Ubuntu 20.04 镜像运行并安装了 gcc
或其他软件包后,这些修改是持久的。也就是说,下次启动同一个容器时,这些安装过的软件包依然会保留。
理解 Docker 容器的持久化行为
-
容器内的更改是持久化的:当你在容器中安装软件或进行其他更改时,这些更改会保存在容器的文件系统中。只要你不删除这个容器,再次启动时,之前的修改都会保留。
-
镜像是只读的:镜像本身是一个只读模板,容器是基于镜像启动的。当你运行一个容器并做出更改时,这些更改是在容器的可写层上进行的,而不影响底层的只读镜像。
举例说明
假设你通过以下命令创建了一个容器并安装了 gcc
:
bash
docker run -it --name ubuntu20.04_container ubuntu:20.04 /bin/bash
# 在容器中执行
apt update
apt install gcc -y
此时,gcc
已经安装在容器内。然后你退出容器:
bash
exit
接下来你可以通过以下命令再次启动并进入这个容器:
bash
docker start -i ubuntu20.04_container
进入容器后,gcc
依然存在,你可以直接运行 gcc
或 uptime
命令。
需要注意的事项
-
如果删除容器,所有更改都会丢失 :如果你使用
docker rm
命令删除了容器,容器中所有的更改(包括安装的软件)都会丢失。如果你想保存这些更改,应该使用docker commit
命令将容器的当前状态保存为一个新的镜像。 -
新的容器不会保留以前容器的更改:如果你基于相同的 Ubuntu 20.04 镜像启动一个新的容器,新的容器不会保留你在旧容器中的任何更改。
容器和镜像之间的关系是 Docker 运行的核心概念之一。简单来说:
- 镜像(Image) 是一个静态的、只读的模板,包含了文件系统、操作系统、应用程序及其依赖项等内容。
- 容器(Container) 是镜像的一个运行实例,它在镜像的基础上添加了一个可写层,并运行着镜像中定义的应用程序或操作系统。
更详细的理解
1. 镜像(Image)
- 只读:镜像是只读的,不能直接修改。
- 构建块:镜像是由多个"层"构成的,每一层代表一次文件系统的更改(比如添加文件、安装软件等)。镜像的这些层是叠加起来的,最终构成了一个完整的文件系统。
- 不可变性:由于镜像是不可变的,它们可以被重复使用和共享。比如,你可以从 Docker Hub 拉取一个官方的 Ubuntu 镜像,然后基于这个镜像创建容器。
2. 容器(Container)
- 运行时实例:容器是基于镜像的一个运行实例。当你启动一个容器时,Docker 会基于指定的镜像创建一个新的可写层,并在这个层上运行应用程序。
- 可写层:容器的可写层使得你可以在运行中的容器中修改文件系统,例如安装软件、创建文件等。这些更改是临时的且独立于镜像本身。
- 短暂或持久:容器可以是短暂的(即使用完就删除)或者持久的(保存更改,下次启动时继续使用)。
3. 容器与镜像的关系
- 镜像是容器的基础:容器是在镜像的基础上创建的。你可以把镜像理解为一个蓝图,而容器则是按照这个蓝图建造的房子。
- 多容器共享同一个镜像:同一个镜像可以启动多个容器,每个容器都有自己的独立可写层,这意味着这些容器之间的更改互不影响。
- 从容器创建镜像 :如果你在容器中进行了重要的更改,并且希望保存这些更改,你可以使用
docker commit
命令将当前容器保存为一个新的镜像。
4. 举个例子
- 镜像:你有一个 Ubuntu 20.04 的镜像,它是一个标准的、最小化的 Ubuntu 文件系统,没有任何修改。
- 容器 :当你基于这个镜像启动一个容器时,你进入了一个全新的 Ubuntu 环境。你可以在这个容器中安装
gcc
,创建文件等。所有这些操作只影响这个容器的可写层,而不影响原始的 Ubuntu 20.04 镜像。
总结
- 镜像:像是一个模板,静态且不可变。
- 容器:是基于镜像创建的动态实例,带有可写层。
通过镜像和容器的这种关系,Docker 实现了应用程序的轻量级虚拟化和高效部署。
你可以基于现有的容器创建一个新的镜像,并将这个镜像作为基础镜像分享给其他人。这样,其他人可以使用这个镜像来启动具有你所做更改和安装的软件的容器。
创建新镜像的步骤
-
启动并修改容器:首先,你基于某个镜像(例如 Ubuntu 20.04)启动一个容器并在其中进行修改,比如安装软件、配置环境等。
bashdocker run -it --name my_container ubuntu:20.04 /bin/bash apt update apt install gcc -y
-
退出容器:完成修改后,你可以退出容器。
bashexit
-
提交容器为新镜像 :使用
docker commit
命令将该容器的当前状态保存为一个新镜像。bashdocker commit my_container my_custom_image
这里
my_custom_image
是你新镜像的名称。 -
查看新镜像:你可以通过以下命令查看你的新镜像是否已创建:
bashdocker images
-
分享镜像:如果你想分享这个新镜像,可以将其推送到 Docker Hub 或者打包成 tar 文件:
-
推送到 Docker Hub:
-
首先,确保你已经登录 Docker Hub:
bashdocker login
-
然后推送新镜像:
bashdocker tag my_custom_image your_dockerhub_username/my_custom_image docker push your_dockerhub_username/my_custom_image
-
-
导出为 tar 文件:
bashdocker save -o my_custom_image.tar my_custom_image
这样,其他人可以使用
docker load
命令加载这个镜像:bashdocker load -i my_custom_image.tar
-
总结
通过这种方式,你可以将自己定制的环境打包成镜像,方便与他人分享,并保证他们能够在相同的环境下运行你的应用程序或代码。这样做不仅提高了开发效率,也简化了部署过程。