通俗易懂,十分钟让你了解并上手 Docker
- 一、Docker 能拿来解决什么问题
- 二、Docker 的概念与模型
- 1. 容器化技术
- 2. 镜像的概念
- 3. Docker与虚拟机
- 三. Docker的使用
- 1. 环境安装
- 2. 制作镜像
- 3. 镜像管理
- (1) 图形界面
- (2) 命令行
- 四、Docker 常用命令及其作用
开了云原生专栏很久,但一直没怎么更新,今天就来更新一篇Docker的。主要面向新人,争取十分钟让完全新手了解Docker的作用、原理以及基本的操作
📕作者简介:战斧,从事金融IT行业,有着多年一线开发、架构经验;爱好广泛,乐于分享,致力于创作更多高质量内容
📗本文收录于 云原生专栏,有需要者,可直接订阅专栏实时获取更新
📘高质量专栏 MyBatis专栏 、RabbitMQ、Spring全家桶 等仍在更新,欢迎指导
📙Zookeeper Redis kafka docker netty等诸多框架,以及架构与分布式专题即将上线,敬请期待
一、Docker 能拿来解决什么问题
我们知道,每一个火爆的技术之所以流行,必然有其原因。而其中占大头的,莫过于能帮大伙解决痛点问题,那么Docker能为开发者解决什么问题呢?
其实在软件开发过程中,不知道大家是否遇到这样一些痛点,笔者简单举两个例子:
① 比如笔者之前一次任务要求生成并导出一个PDF文件,在开发环境没问题,但到了测试环境,发现所有的中文字符全部成了空白,检查后发现测试环境缺乏对应的字体,导致汉字无法显示
② 又比如一次临时的批量部署事件,由于原始机器太少性能吃紧,所以紧急征用了不少环境,本身每个环境一一部署就很麻烦了,而且这些环境很多底座及设置都不尽相同,比如有的是JDK8,有的是JDK11。这样的临时部署事件,环境配置也让大家非常疲惫
那么,Docker 就能帮我们解决以上那些问题。简而言之,Docker的主要作用有三个方面:
-
快速部署:Docker通过将应用程序及其依赖打包到一个镜像中,实现了 一次构建、到处运行 的理念。开发者只需要创建一个Docker镜像,然后在任何支持Docker的环境中运行即可,无需担心环境不一致带来的问题。在开发环境、测试环境和生产环境之间的迁移非常简单,大大减少了部署时间和人力成本。
-
环境一致性:借助Docker的容器化技术,可以实现应用程序在不同环境中的高度一致性。无论是开发者的本地机器还是云服务器,只需要保证Docker环境一致,就可以保证应用程序能够稳定运行。这为开发者提供了一个稳定的开发、测试和部署平台。
-
资源利用率高:传统的虚拟化技术每个虚拟机都需要独立的操作系统,造成了资源的浪费。而Docker采用了轻量级的容器化技术,可以在宿主机上运行多个容器,共享宿主机的操作系统内核,大大提高了资源利用率。同时,容器化技术还能够快速启动和停止容器,进一步提高了资源的利用效率。
当然啦,如果此前你从未接触过Docker,那也许你还有点懵动,不清楚上面这几种作用是怎么实现的,别急,我们将在下面为你陈述。
二、Docker 的概念与模型
我们将从两个方面来诠释Docker,即Docker是什么,以及Docker如何用
1. 容器化技术
谈Docker,就必需先讲讲容器化技术
。简单地说, 就是我们可以将应用程序及其所有的依赖关系打包成一个袋子,然后在任何地方都能够快速打开袋子,然后运行其中的内容,形成一个独立的容器环境,这样的技术就是容器化技术
就如同我们前面举的例子,传统的开发方式,我们需要安装各种软件、库和配置环境,才能保证应用程序能够正常运行。然而由于环境之间存在差异,部署和迁移应用程序非常麻烦。而Docker
的出现解决了这个问题,它可以将应用程序和所有的依赖项打包到一个容器中,形成一个独立、可移植的环境。这意味着开发者只需要关注应用程序本身,而不用担心环境的配置和兼容性。
2. 镜像的概念
我们刚刚在说容器化技术的时候,说到了将应用程序及其所有的依赖关系打包成一个袋子,这个袋子其实就是镜像(Image)
,镜像(Image)
与容器
的关系就像程序
与进程
的关系一样:镜像是一个包裹,包含了运行应用程序所需的所有组件、库、依赖、文件和配置等,容器则是从镜像创建出来的可运行实例,容器可以被启动、暂停、停止
当然,镜像不是杂乱无章的大杂烩。如上图所示,镜像
拥有层级(layer)
概念,每个Docker镜像由多个层级组成,每个层级都包含了一些文件系统的修改,这些层级按照顺序堆叠在一起,每个层级都是只读的,并且可以被多个镜像共享,最底层为bootfs(boot file system) 和 操作系统(如Debian),高层级则是用户程序。这种层级的设计有不少优点:
- 共享资源:当多个镜像共享相同的层级时,可以节省存储空间,因为这些共享层级只需要保存一份。
- 快速构建和部署:当修改镜像时,只需要添加或修改相应的层级,而不是重新创建整个镜像。这样可以大大加快镜像的构建和部署速度。
- 可定制性:每个层级都可以被看作是一个单独的修改记录,因此可以方便地定制镜像,只需基于已有的层级进行修改和添加。
3. Docker与虚拟机
不知道读者朋友们以前是否使用过虚拟机
?有时候我们想在一台机器上多开应用的时候,就可能会用到虚拟机,这样我们就如同拥有了多个独立的机器。而Docker,则可以认为是一种更轻量且高效的虚拟机,为什么说轻量
、高效
,我们可以在下图看一下:
不难看出,虚拟机(VM)在原本的操作系统上加了一层虚拟机监视器,然后又加了一层用户操作系统,我们的程序就是在用户操作系统上运行。而Docker则只有一层Dcoker守护进程,省略了虚拟机中的那一层“用户系统”,也就是说 Docker 的运行依赖于宿主机器的操作系统,这样会导致Docker比虚拟机更轻盈,执行效率也更高,但同样也限制了跨平台的能力,也即虽然Docker可以跨平台运行,但容器内的应用程序可能会因为不同的操作系统而产生差异或不兼容的问题,比如你为Window环境准备的内容,可能就无法通过Docker在Linux上运行
更具体的对比可以看这张表
区别 | Docker | 虚拟机 |
---|---|---|
构建方式 | 使用容器化技术,通过镜像构建容器。 | 使用Hypervisor技术,将物理服务器划分为多个虚拟机。 |
启动速度 | 秒级启动速度,可以快速部署和运行应用程序。 | 分钟级启动速度,启动虚拟机需要时间。 |
性能 | 接近原生性能,容器与宿主机共享操作系统内核和硬件资源。 | 较慢,因为虚拟机需要模拟硬件并运行完整的操作系统。 |
系统资源使用 | 占用的系统资源较少,容器可以共享宿主机的操作系统内核。 | 耗费较多的系统资源,每个虚拟机都需要完整的操作系统。 |
部署与扩展 | 容易部署和扩展,可以通过编排工具自动化管理容器。 | 部署和扩展相对复杂,需要管理不同的虚拟机和操作系统实例。 |
网络 | 容器可以直接访问宿主机的网络接口,网络更直接。 | 虚拟机需要通过虚拟网络进行通信,网络相对间接。 |
隔离性 | 容器间相互隔离,但容器与宿主机共享操作系统内核。 | 虚拟机间相互隔离,每个虚拟机都有独立的操作系统内核。 |
应用程序数量 | 可以在同一台宿主机上运行数十到数百个容器。 | 受限于宿主机的物理资源,一般只能运行数个虚拟机。 |
部署环境 | 适用于微服务架构和容器化的应用程序。 | 适用于传统应用程序和需要完整操作系统的应用程序。 |
适用场景 | 开发、测试、部署和分发应用程序的环境。 | 测试、隔离和运行不同操作系统的应用程序的环境。 |
三. Docker的使用
现在我们基本上知道了Docker的意思,知道了镜像
和容器
的概念,但是我们可能还有几个疑惑,比如
- Docker有环境要求吗?
- 镜像怎么传到其他机器的?
- 镜像是怎么制作的?
让我们带着疑问,来看看Docker真正在使用中的一个模型,然后进行解释。
1. 环境安装
首先,想要在机器(Host)上运行起一个Docker容器,机器上必需先安装上Docker,可以参考另外C站的一篇博文进行安装【Linux部署Docker安装步骤详解及问题解决】,这样你才能获得daemon
,来管理Docker对象(例如容器、镜像、网络等)
2. 制作镜像
当然,如果你想自己制作个镜像,当然也是可以的。简单来说,就是在你的项目目录下创建一个 Dockerfile
文件然后编写它,指定基础镜像、维护者信息和构建命令等。Dockerfile 使用一系列指令来描述构建过程,比如 FROM
、RUN
、COPY
、EXPOSE
等。以笔者手头的一份java项目的Dockerfile文件为例,并逐行解释
# 指定基础镜像为openjdk:8
FROM openjdk:8
# 设置工作目录为/home
WORKDIR /home
# 切换用户为root
USER root
# 设置环境变量
ENV PROFILE="dev"
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV PARAMS=""
# 将宿主机target目录下的以.jar结尾的文件复制到镜像的/home目录下,并重命名为app.jar
COPY /target/*.jar /home/app.jar
# 暴露容器的80端口
EXPOSE 80
# 创建软链接,设置时区为上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
# 将一条命令(单引号中的内容)写入entrypoint.sh文件。不难看出,该命令用于创建目录并运行Java应用。
RUN echo -e 'mkdir -p ./logs/gc && java $JAVA_OPTS -jar ./app.jar --spring.profiles.active=$PROFILE $PARAMS' > entrypoint.sh
# 设置容器启动时执行的入口命令为sh entrypoint.sh,即运行entrypoint.sh脚本。
ENTRYPOINT ["sh", "entrypoint.sh"]
编写完· Dockerfile
后,在终端或命令行中使用 docker build 命令来构建镜像
3. 镜像管理
有了环境后,我们还要获取一个镜像。一般来说镜像可以从Docker hub
下载,Docker Hub
是Docker官方提供的一个在线的仓库服务,在Docker Hub上,用户可以找到各种官方镜像。当然,你也可以自己指定从一些三方、或私人仓库private resistry
下载镜像,如果你使用过maven,应该能理解这种公共或私有仓库的关系。一般来说,可以通过命令或界面来完成。
(1) 图形界面
下载图形界面,比如笔者是windows,可以在官网下载 https://docs.docker.com/desktop/install/windows-install/
其详细安装及操作可参见另外一位C站大佬的文章 《Docker Desktop 安装使用教程》
(2) 命令行
-
下载镜像:使用
docker pull
命令下载一个镜像。例如,要下载Ubuntu镜像,可以运行
docker pull ubuntu。 -
上传镜像:首先,您需要将本地镜像标记为您的Docker Hub或其他镜像仓库的地址。使用
docker tag
命令来标记镜像。例如,如果您要上传名为"myimage"的镜像到Docker Hub上的"myusername"库中,可以运行
docker tag myimage myusername/myimage
然后,使用docker push
命令上传镜像
docker push myusername/myimage
四、Docker 常用命令及其作用
接下来我们来介绍一些Docker的常用命令及其作用:
- docker run:
运行一个容器。 示例:docker run -d -p 8080:80 nginx
会在后台运行一个Nginx容器,并将主机的8080端口映射到容器的80端口。
- docker ps:
列出正在运行的容器。 示例:docker ps 显示正在运行的容器的列表,包括容器ID、状态、端口映射等信息。
- docker stop:
停止一个正在运行的容器。 示例:docker stop <容器ID> 会停止指定的容器。
- docker rm:
删除一个容器。 示例:docker rm <容器ID> 会删除指定的容器。
- docker images:
列出本地的镜像。 示例:docker images 显示本地的镜像列表,包括镜像ID、标签、大小等信息。
- docker pull:
从Docker仓库中拉取镜像。 示例:docker pull nginx 会从Docker仓库拉取最新版本的Nginx镜像。
- docker push:
推送一个镜像到Docker仓库。 示例:docker push myusername/myimage
会将名为myimage的镜像推送到Docker仓库。
- docker build:
构建一个镜像。 示例:docker build -t myimage:tag .
会在当前目录下的Dockerfile文件中构建一个名为myimage的镜像。
- docker exec:
在运行的容器中执行命令。 示例:docker exec -it <容器ID> bash 可以在容器中打开一个交互式的bash终端。
更详尽的命令可以在官网的参考文档:https://docs.docker.com/reference/cli/docker/