Docker 初学者基础知识
在我的最新文章中,我讨论了 Vagrant 以及它如何帮助我们在几分钟内创建虚拟机。但如果它能更快、更好、更可定制呢?让我们学习如何使用 Docker 轻松开发、部署和运行应用程序!
介绍
如果您使用 Google 搜索Docker,您会发现 Docker 是一个使用操作系统级虚拟化来创建自包含容器的软件平台。
幸运的是,在这里我将用简单的英语向您解释这是什么意思。
您可能之前使用 Oracle VM 或Vagrant创建过多个虚拟机。Docker 与之类似(但更胜一筹,稍后会详细介绍)。
使用 Docker,我们选择一个镜像(可以把 Docker 镜像想象成一个配方)并下载它。然后,我们创建该镜像或容器的实例,这非常类似于虚拟机。
图像:
用于创建一个或多个容器的包或模板
容器:
图像的实例彼此隔离,具有自己的环境。
让我们看看它的实际效果。这是一个 Docker 镜像代码:
FROM ubuntu:23.04
RUN apt-get update
RUN apt-get install -y curl nginx
还记得我说过 Docker 镜像就像一个菜谱吗?在这个镜像或菜谱中,Docker 获取了 Ubuntu 23.04 版本,更新了 SO,然后安装了curl和nginx。
当然,这是一个简短的 Docker 镜像版本,但它帮助我们直观地了解 Docker 的含义。
现在,有了这个图像,我们可以创建一个容器(想象一个虚拟机),它将创建一个已经更新的 Linux Ubuntu VM,带有 curl 和 nginx。
公司里的所有开发人员都可以使用同一个镜像来安装相同的程序、软件包和版本。再也不会出现“但是……它在我的电脑上能用!”的情况了;现在每台电脑的配置都一致了。
Docker 与虚拟机
但是...如果 Docker 创建了一个类似 VM 的容器,为什么我们不只使用虚拟机呢?
我可以从底层解释 Docker 容器为何比虚拟机更好,甚至可以从其他类似网站获取一些很酷的信息图表,并解释 Docker 对每个容器使用相同的内核,使其轻量且快速,只需几秒钟即可旋转一个容器:
但是使用 Docker 和 Docker 容器有一个很大的好处:
假设您想要开发 21.1 NodeJS:您创建自己的 Docker 镜像,在其中获取 Ubuntu 镜像,更新它,安装所有与 NodeJS 相关的内容,然后将该镜像分发给开发团队。
在正常设置中,您必须上传 NodeJS 应用程序,将其部署到您的服务器上,并且您必须确保服务器具有所有依赖项并且其 NodeJS 与您的服务器兼容。
你不会想打赌的。
使用 Docker,我们可以创建一个 Docker 镜像,将其上传到与 Docker 兼容的服务器,就这样。
Docker 服务器并不关心你使用的是什么 Linux、安装了什么软件包,或者你的应用程序是什么语言:它只需要运行镜像。就是这样。
我要强调一下:我们不关心服务器安装了什么。我们只需上传并运行 Docker 镜像。这就是我们要做的。
安装
您可以安装 Docker Desktop(一个 GUI Docker 应用程序),但是我们这些坚韧的开发人员使用适当的终端工具,因此您将安装 Docker Engine(Docker 的终端版本)。
玩笑归玩笑,你可以安装任何你想要的:Docker Desktop或Docker Engine,只要确保遵循操作系统的说明即可。例如,对于基于 Debian 的发行版(例如 Ubuntu):
卸载以前的 Docker 版本
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
安装 Dockercurl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh
检查 Docker 是否已安装sudo docker version
让我们进行测试。在终端中运行以下命令:
sudo docker run docker/whalesay cowsay boo
重要提示:每个 Docker 命令都需要 sudo 权限。你可以将用户添加到docker组,但尽管如此,它仍然会不断请求 sudo 权限。我发现,运行该命令后sudo chmod 666 /var/run/docker.sock
,就不会再要求你输入 sudo 权限了(你可以使用类似的命令,例如chmod +x)。
基本命令
我们已经启动并运行了 Docker。让我们看几个基本命令。如果你想要的话,这就是你的日常工作:
列出所有图像docker images
从镜像下载或执行容器docker run <IMAGE_NAME>
下载特定版本docker run <IMAGE_NAME>:<VERSION>
在后台执行容器docker run -d <IMAGE_NAME>
将容器从后台移到前台docker run attach <ID>
执行命令docker run ubuntu cat /etc/*release*
docker run ubuntu sleep 15
下载图像以便稍后运行docker pull <IMAGE_NAME>
在docker容器内执行命令docker exec <COMMAND>
连接到容器的 bashdocker run -it <IMAGE_NAME> bash
列出所有正在运行的容器docker ps
列出所有容器,无论是否正在运行docker ps -a
运行一个容器并链接到另一个容器:docker run -p <PORT_LOCAL>:<PORT_DEFAULT> --link <IMAGE_NAME_TO_LINK>:<IMAGE_NAME_TO_LINK> <IMAGE_NAME>
docker run -p 5000:80 --link redis:redis voting-app
以 JSON 格式获取图像或容器的详细信息docker inspect <NAME_OR_ID>
从后台运行的容器获取日志docker logs <NAME_OR_ID>
获取图像的所有图层docker history <IMAGE_NAME>
停止容器docker stop <IMAGE_NAME_OR_ID>
永久移除容器docker rm <IMAGE_NAME_OR_ID>
永久删除未使用的图像docker rmi <IMAGE_NAME>
从 Dockerfile 构建镜像docker build . -t <NAME>
环境变量docker run -e <VARIABLE>=<VALUE> <IMAGE_NAME>
docker run -e APP_COLOR=blue simple-webapp-color
示例:Jenkins 容器
让我们使用一个现实生活中的例子:使用 Jenkins 容器。
在以后的文章中,我将更深入地讨论 Jenkins 及其功能,但 Jenkins 是一款出色的 DevOps CI/CD 工具。让我们下载 Jenkins 并在计算机上运行它:
docker run jenkins/jenkins # This downloads and runs jenkins
docker ps # Get the container ID and port
docker inspect <CONTAINER_ID> # Get the container IP
使用以下命令在您的虚拟机中打开浏览器:docker run -p 8080:8080 jenkins/jenkins # Map the port
使用以下命令在主机中打开浏览器:
在这里,我们在 Ubuntu 虚拟机中安装并下载 Docker 镜像并运行它。我们可以通过打开浏览器并使用 Docker 容器的 IP 和端口在虚拟机中查看 Jenkins,但通过映射端口,我们可以在主机上打开 Jenkins。
其结构如下:
带有 Windows 的主机 -> Linux VM -> 在 Linux 中运行的 Docker 容器
现在,Linux 正在运行一个轻量级的 Docker 容器,我们可以从 Windows 机器访问它。是不是很棒?
数据持久化
我们停止了 Jenkins 容器,第二天又恢复它继续工作。但是我们丢失了所有内容。发生了什么???
Docker 本身不具备数据持久性。
容器使用自己的文件夹(Jenkins 上的/var/jenkins_home文件夹,MySQL 上的/var/lib/mysql 文件夹等等),但是当你停止容器并再次运行镜像时,你实际上是在从头创建一个容器。我们该怎么办?
我们可以通过链接运行 Docker 的操作系统中的文件夹和容器的文件夹来实现数据持久化。
mkdir my_jenkins_data
docker run -p 8080:8080 -v /home/<USERNAME>/my_jenkins_data:/var/jenkins_home jenkins/jenkins
在这里,我们创建了一个名为my_jenkins_data的文件夹,并将其与 Jenkins 文件夹/var/jenkins_home链接,Docker 将任何更改存储在该文件夹中。
因此,如果我们再次运行该命令,我们将创建一个新的容器,链接存储的信息,就像我们正在恢复我们的容器一样。
卷的数据持久性
我们可以简化这个过程。我们不需要为文件夹指定一个长字符串,而是可以让 Docker 通过在/var/lib/docker/volumes/*中创建卷来管理它们。
创建卷docker volume create test_volume
这将在 /var/lib/docker/volumes/test_volume 中创建一个卷docker run -v test_volume:var/lib/mysql mysql
我们也可以使用现代方法,它更长但更具声明性和详细性:docker run / --mount type=bind, source=/data/mysql, target=/var/lib/mysql mysql
最后的想法
正如我们刚刚看到的,Docker 之所以优秀,有以下几个原因:
-
隔离性:Docker 可以让应用程序与底层系统隔离,保证不同环境下的一致性。
-
效率:通过使用容器化来优化资源利用率,从而更有效地利用系统资源。
-
可移植性:Docker 容器可以在任何安装了 Docker 的机器上运行,从而可以轻松地跨不同环境部署应用程序。
-
可扩展性:使用 Docker,可以根据需求增加或减少容器数量,轻松扩展应用程序。
-
一致性:Docker 确保开发、测试和生产环境一致,减少了“它在我的计算机上可以正常工作”的问题。
-
生态系统:Docker 拥有丰富的生态系统,其中包含补充容器化的各种工具和服务,使其成为应用程序部署和管理的多功能平台。
-
部署:Docker 使部署更加轻松、安全。我们无需管理软件包及其版本,只需将 Docker 镜像上传到服务器即可。