在部署大型项目时,常常面临多组件、复杂的依赖关系和不同环境之间的差异,这些因素可能导致以下问题:
复杂的依赖关系: 由于项目组件众多,各个组件之间的依赖关系变得复杂,容易出现版本不匹配或兼容性问题。
兼容性问题: 项目在不同的环境中可能会遇到兼容性挑战,导致在一个环境中正常运行的组件在另一个环境中出现问题。
环境差异: 开发、测试和生产环境之间存在差异,可能涉及操作系统、库版本、配置等方面的不一致性,增加了部署的复杂性。
这些挑战使得项目部署变得复杂且容易出错。为了解决这些问题,引入Docker技术是一个有效的方案。Docker的容器化特性能够提供一致的运行环境,简化依赖管理,并减轻不同环境之间的差异性,从而提高部署的可靠性和效率。在接下来的内容中,我们将深入了解Docker的基本概念以及如何利用Docker解决这些项目部署的挑战。
Docker 是一种开源的容器化平台,旨在简化应用程序的开发、交付和部署过程
。通过使用容器技术,Docker 能够将应用程序、所有依赖项以及程序运行所需要的环境
打包成一个独立的容器。这个容器包含了运行应用所需的一切,包括操作系统、库和代码等等。这种打包的方式使得应用程序在任何环境中都能够以一致的方式运行,从而实现了跨平台、可移植和快速部署的优势。
Docker 是一项旨在实现快速交付应用和高效运行应用的技术。它提供了以下主要特性:
容器化打包: Docker允许将程序、其依赖以及运行环境一同打包成一个独立的镜像。这个镜像包含了应用程序所需的一切,从操作系统到所有依赖库,形成了一个可移植的、一致的运行环境。
跨平台移植性: 由于 Docker 镜像是独立的、轻量级的打包,因此可以轻松迁移到任意支持 Docker 的 Linux 操作系统,无需担心环境差异性问题。
沙箱隔离: 运行时,Docker 利用沙箱机制为每个容器创建独立的运行环境,使得各个应用程序在容器内互不干扰。这种隔离性确保了安全性和可靠性。
便捷的管理命令: Docker 提供了简单而强大的命令行工具,用户可以使用一行命令完成启动、停止、移除容器等操作。这种便捷性提高了应用程序的开发、测试和部署效率。
总体而言,Docker 为开发人员提供了一种先进的、可移植的容器化解决方案,通过将应用程序及其运行时环境打包成镜像,实现了快速部署和跨平台运行的便利性。同时,沙箱隔离机制确保了多个应用程序之间的独立性,使得Docker成为现代应用开发和部署的理想选择。
Docker和虚拟机是两种常见的容器化技术,它们在实现虚拟化和隔离的方式以及性能表现上存在一些区别。在理解Docker和虚拟机之前,首先我们可以简单了解它们的层次结构:
通过上图可以发现虚拟机是使用 Hypervisor 在操作系统上模拟出计算机硬件,然后再在这个虚拟硬件上安装的操作系统;而 Docker 容器则是直接运行在操作系统上的。因此 Docker 的性能会远远优于虚拟机。
下面我们来比较一下 Docker 和虚拟机的特性:
特性 | Docker | 虚拟机 |
---|---|---|
性能 | 接近原生 | 性能较差 |
硬盘占用 | 一般为MB | 一般为GB |
启动 | 秒级 | 分钟级 |
Docker的优势:
性能: Docker容器直接运行在宿主操作系统的内核上,因此性能接近原生,而虚拟机需要在Hypervisor的管理下运行,性能相对较差。
硬盘占用: Docker镜像是轻量级的,通常只有MB级别,而虚拟机的镜像则往往是GB级别,因此Docker在硬盘占用上更为高效。
启动速度: Docker容器启动非常迅速,可以达到秒级的启动时间,而虚拟机的启动则需要较长的时间,通常是分钟级。
总体而言,Docker适用于快速部署、轻量级应用,而虚拟机则更适合需要完全隔离的复杂应用。选择使用哪种技术取决于具体的应用场景和需求。
在Docker的世界里,镜像和容器是两个核心概念,理解它们是使用 Docker 的关键。
镜像是什么?
镜像是一个轻量级、独立的可执行软件包,包含运行应用程序所需的一切:代码、运行时、系统工具、系统库,以及设置。简单来说,镜像就是一个应用程序的打包。
构成要素:
特点:
例子:
容器是什么?
容器是镜像的运行实例。可以将容器视为一个轻量级、独立的可执行包,包含应用程序、运行时和系统工具,并根据镜像的定义执行。
特点:
例子:
镜像托管平台:
DockerHub:
其他镜像托管平台:
总之,理解镜像和容器的关系,以及它们在 Docker 中的作用,是使用 Docker 进行应用开发和部署的基础。 Docker 的成功部分归功于这种轻量级、可移植的容器化技术,使得应用程序的构建、分发和运行变得更加简单和高效。
Docker的架构设计简单而灵活,分为客户端和服务端两部分,它们协同工作以实现容器的创建、运行和管理。
客户端(Client)
客户端是用户与Docker交互的界面。用户可以通过命令行、图形界面或者使用 Docker 提供的API与服务端通信,发送指令来管理 Docker。
服务端(Server)
服务端是 Docker 的守护进程,负责处理来自客户端的指令,管理 Docker 的各项工作。服务端的主要组件包括:
Docker Daemon: 守护进程,运行在主机上,负责管理容器的创建、运行和停止等操作。它还负责与其他Docker守护进程通信,以及与客户端通信。
Docker REST API: 客户端和守护进程之间的通信通过REST API进行。客户端可以通过REST API向守护进程发送命令,实现与Docker的交互。
Docker Registry: 用于存储Docker镜像的服务。Docker官方提供了Docker Hub作为默认的公共Registry,用户也可以使用私有Registry或其他公共Registry存储和分享镜像。
架构图示
在这个架构中,客户端和服务端可以运行在同一台主机上,也可以通过网络连接在不同的主机上。当客户端发送Docker命令时,它们通过REST API与服务端进行通信,服务端根据指令执行相应的操作。
交互流程
客户端发送命令: 用户通过命令行或其他工具发送Docker命令,如创建镜像、运行容器等。
命令发送至服务端: 客户端将命令发送至服务端,通过REST API进行通信。
服务端执行命令: Docker Daemon接收到命令后,执行相应的操作,如创建或管理容器、拉取或推送镜像等。
结果返回给客户端: 服务端执行完命令后,将结果返回给客户端,用户可以看到执行结果。
Docker的这种CS(Client-Server)架构使得用户可以通过简单的命令与Docker进行交互,同时服务端负责具体的管理和操作,使得整个系统更加模块化和易扩展。
Docker是一款强大的容器化平台,为了在CentOS上使用Docker,我们将按照以下步骤进行安装。
如果之前安装过 Docker 的旧版本,可以通过以下命令卸载:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine \
docker-ce
安装必要的工具和依赖:
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
添加 Docker 的官方存储库。这里我们使用阿里云的镜像加速地址:
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装最新版本的 Docker 引擎:
sudo yum install docker-ce docker-ce-cli containerd.io
启动 Docker 引擎并设置开机启动:
sudo systemctl start docker
sudo systemctl enable docker
运行以下命令验证 Docker 是否正确安装:
docker --version
docker info
为了提升 Docker 镜像的下载速度,配置镜像加速器。以阿里云为例,前往阿里云容器镜像服务注册账号并获取加速地址。然后在/etc/docker/daemon.json
中添加以下内容:
{
"registry-mirrors": ["https://your-registry-mirror"]
}
替换https://your-registry-mirror
为你的加速地址。
完成上述步骤后,我们的 CentOS 系统就成功安装并配置好了 Docker。现在,就可以通过运行 docker run hello-world
测试Docker是否正常工作。
Docker 的操作主要分为三个方面:镜像操作、容器操作和数据卷管理。下面详细介绍这三方面的相关命令。
在Docker的世界中,镜像是应用程序的打包和分发单位。理解并熟练使用与镜像相关的命令是使用Docker的关键。本文将详细介绍一些常见的镜像操作命令。
镜像名称解析
在Docker中,镜像名称通常由两部分组成:[repository]:[tag]
。如果不指定tag
,默认使用latest
,表示最新版本的镜像。例如,mysql
的镜像名称:
镜像操作命令概览
从上图可以发现,镜像命令主要包括以下几种:
docker pull
: 从远程仓库拉取镜像。
docker pull image_name
docker push
: 将本地镜像推送到远程仓库。
docker push image_name
docker build
: 根据Dockerfile构建镜像。
docker build -t image_name .
docker save
: 将镜像保存为一个tar压缩包。
docker save -o image_name.tar image_name
docker load
: 从一个tar压缩包中加载镜像。
docker load -i image_name.tar
DockerHub是Docker官方的镜像仓库,提供了大量的官方和社区维护的镜像。以下是一个从 DockerHub 拉取nginx 镜像的示例:
docker pull nginx
上述命令将从 DockerHub 下载最新版本的 nginx 镜像到本地。然后使用 docker images
命令则可以查看当前已经存在的镜像:
如果需要特定版本的镜像,可以使用:
docker pull nginx:version
将version
替换为需要的具体版本即可。
首先,关于 save
和 load
的语法,我们可以使用 --help
选项来进行查看:
save
命令:
docker save --help
可以发现,save
命令的作用是将镜像保存为一个tar
格式的压缩包,使用 -o
选项代表STDOUT
标准输出,将其写入到文件中。
例如,保存上面的nginx
镜像到磁盘:
docker save -o nginx.tar nginx:latest
load
命令:
docker load --help
可以发现,load
命令的作用是将一个tar
格式的压缩包加载为一个 Docker 镜像,使用 -i
选项代表STDIN
标准输入,将其写入到指定文件中,-q
选项则不会输出日志到终端。
例如,加载刚才的 nginx.tar
压缩包:
容器是Docker的运行实例,是镜像的具体执行环境。了解并熟练使用容器相关的命令是使用Docker的核心部分。接下来,我们将详细介绍一些常见的容器操作命令。
容器操作命令如下图所示:
让我们逐一了解这些命令:
docker run
: 运行容器。
docker run options image_name
docker pause
: 暂停容器。
docker pause container_id
此命令可以暂停运行中的容器,使其进程挂起。
docker unpause
: 恢复容器。
docker unpause container_id
与docker pause
相对应,该命令用于恢复被暂停的容器。
docker stop
: 停止容器。
docker stop container_id
通过此命令,你可以停止运行中的容器,但容器实例仍然存在。
docker start
: 启动已停止的容器。
docker start container_id
使用该命令,你可以启动之前停止的容器。
docker rm
: 移除容器。
docker rm container_id
通过此命令,你可以删除已经停止的容器实例。请注意,删除容器不会删除镜像。
docker exec
: 在运行中的容器中执行命令。
docker exec options container_id command
该命令用于在正在运行的容器中执行特定命令,例如:
docker exec -it container_id /bin/bash
上述命令将在容器中打开一个交互式的bash shell。
docker logs
: 查看容器日志。
docker logs container_id
此命令用于查看容器的输出日志。
docker ps
: 列出运行中的容器。
docker ps options
通过此命令,可以列出正在运行的容器。使用-a
选项可以列出所有容器,包括已停止的。
这些命令覆盖了 Docker 容器操作的核心方面,通过它们,可以方便地管理和使用 Docker 容器。在实践中,根据具体需求巧妙组合这些命令,可以更加高效地运行和管理容器。
补充:暂停
pause
和停止stop
的区别说明:
docker pause
和 docker stop
是两个不同的命令,它们的作用分别是暂停容器和停止容器。下面分别说明它们之间的区别:
docker pause
:
docker pause container_id
docker stop
:
docker stop container_id
区别总结:
docker pause
暂停容器,冻结容器状态,容器中的数据保留。docker stop
停止容器,终止容器内的所有进程,容器中的数据保留。在选择使用这两个命令时,需要根据具体的需求来决定。如果需要在保留容器状态的同时暂时停止容器中的所有进程,可以使用 docker pause
;如果希望完全停止容器的运行,释放资源,可以使用 docker stop
。
通过下面命令,可以在新的容器中运行一个 nginx
镜像。例如:
docker run -d -p 8080:80 --name my-nginx nginx:latest
说明:
-d
选项:让容器在后台运行;-p
选项:将宿主机的 8080 端口与容器的 80 端口进行映射,即访问宿主机的 8080 端口即可访问到容器的 80 端口;--name
选项:指定容器的名称,需要保证唯一;可以使用 docker ps
命令查看当前运行中的容器:
另外,为了验证 nginx
容器成功启动并运行了,可以在浏览器中使用 宿主机IP:8080
进行访问:
此时出现了 nginx
的欢迎页面,则说明成功启动并运行容器了。
docker exec
命令进入容器的内容:docker exec -it my-nginx bash
说明:
-it
给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互;my-nginx
:要进入的容器的名称;bash
:开启 linux
终端交互的命令。如果我们想要使用 vim
进行修改的话,发现 Docker 容器并没有提供 vim
编辑器,另外我们也可以发现其实 Docker 容器也只提供了少量的命令,原因在于保持容器的轻量化。
此时,我们可以使用 sed
命令进行修改:
# sed
sed -i 's#Welcome to nginx#Docker 非常简单!#g' index.html
sed -i 's###g' index.html # 修改编码方式为 UTF-8
在容器化应用中,容器与其数据之间的耦合可能带来一些问题:
为了解决这些问题,可以使用 Docker 的数据卷。
数据卷(Volume)是一个可以在容器之间共享和重用的目录,它存在于宿主机而不是容器内。通过数据卷,将宿主机文件系统中的某个目录与容器中的目录进行映射,实现数据的共享和持久化。
可以发现,其实就是通过数据卷帮助宿主机文件系统中的文件与 Docker 容器中的文件建立了映射关系。
Docker 提供了一系列的命令来管理数据卷,基本语法如下:
docker volume [COMMAND]
其中,COMMAND
可以是以下几个操作之一:
下面将详细介绍其中的一些常用命令。
要创建一个数据卷,可以使用 docker volume create
命令:
docker volume create my_volume
上述命令将创建一个名为 my_volume
的数据卷。
使用 docker volume inspect
命令可以查看一个或多个数据卷的详细信息:
docker volume inspect my_volume
使用 docker volume ls
命令可以列出所有的数据卷:
docker volume ls
要删除一个或多个指定的数据卷,可以使用 docker volume rm
命令:
docker volume rm my_volume
使用 docker volume prune
命令可以删除未被使用的数据卷:
docker volume prune
上述命令将提示是否删除未使用的数据卷,确认后将执行删除操作。
通过这些数据卷的管理命令,可以更加灵活地处理容器中的数据,实现数据的持久化和共享。在实际应用中,数据卷是非常有用的特性,尤其是对于需要持久化存储的应用场景。
docker volume create html
docker volume ls
html
的详细信息docker volume inspect html
可以发现,html
的宿主机中的挂载点为:/var/lib/docker/volumes/html/_data
。
我们在创建容器时,可以通过 -v
参数来挂载一个数据卷到某个容器目录:
docker run \
--name my-nginx \
-v html:/usr/share/nginx/html \
-p 8080:80 \
-d \
nginx:latest
Docker 镜像是一个包含应用程序及其运行所需组件的轻量级、可执行的软件包。它的文件结构是分层的,每一层都包含了对文件系统的一些更改。让我们深入了解镜像文件的结构。
- 镜像的层次结构
镜像的层次结构由多个层组成,如下图所示:
这些层次分为以下几类:
Base Image 层: 包含基本的系统函数库、环境变量和文件系统。这一层构成了镜像的基础。
Entrypoint 层: 包含应用程序的启动命令。它定义了镜像中应用程序的入口点。
其它层: 在 Base Image 的基础上添加应用程序的依赖、安装程序等,完成整个应用的安装和配置。每一层都是基于前一层的修改。
- 镜像的分层优势
Docker 镜像采用分层的设计有一些优势:
高效的存储利用: 如果多个镜像共享相同的基础层,这一层只需要存储一次,减少了存储空间的占用。
快速的分发: 镜像的分层结构也使得只需要传输发生更改的层,而不是整个镜像,因此可以更快速地分发和部署。
通过这样的分层结构,Docker 实现了镜像的高效管理、存储和传输,使得容器的构建和分发变得更加轻量和快速。
- 什么是 Dockerfile
Dockerfile 是 Docker 中用于构建镜像的脚本文件,它包含了一系列指令,每个指令都会在当前层次上进行修改,形成一个新的层次,最终组合成一个完整的容器镜像。
- Dockerfile 指令
以下是一些常用的 Dockerfile 指令及其说明:
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像,后续的指令将基于这个镜像构建。 | FROM centos:7 |
ENV | 设置环境变量,这些变量可在后续指令中使用。 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk |
COPY | 将文件从构建上下文复制到镜像中的指定路径。 | COPY ./app.jar /usr/app/ |
RUN | 执行 Linux 的 shell 命令,一般用于安装软件包等操作。 | RUN yum install -y gcc |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的。 | EXPOSE 8080 |
ENTRYPOINT | 指定容器中应用的启动命令,容器运行时会调用这个命令。 | ENTRYPOINT ["java", "-jar", "app.jar"] |
更多 Dockerfile 指令和语法细节可以参考官方文档:Dockerfile reference
- Dockerfile 文件
在构建 Docker 镜像时,Docker 会按照 Dockerfile 中的指令逐层构建镜像。每个指令都会在当前层次上进行修改,形成一个新的层次。
例如一个简单的 Dockerfile 如下:
# 使用基础镜像
FROM ubuntu:latest
# 执行一些命令
RUN apt-get update && apt-get install -y \
nginx \
&& rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /app
# 复制文件
COPY . .
# 设置入口命令
CMD ["nginx", "-g", "daemon off;"]
在这个例子中,每一个指令都会在前一个指令的基础上进行修改,构建出一个包含了基础镜像、安装了 Nginx、设置了工作目录和入口命令的完整镜像。
- 使用 Dockerfile 构建镜像
在构建 Docker 镜像时,通过以下命令使用 Dockerfile:
docker build -t my-image:tag path/to/Dockerfile-context
-t
:指定镜像的名称和标签。path/to/Dockerfile-context
:Dockerfile 所在的上下文路径。例如,在一个包含 Dockerfile 的目录中运行以下命令:
docker build -t my-app:1.0 .
上述命令将在当前目录中查找 Dockerfile 文件并构建一个名为 my-app
、标签为 1.0
的镜像。
- 准备工作
docker-demo
拷贝提前准备好的 Java jar 包 docker-demo.jar
文件到 docker-demo
这个目录
拷贝提前准备的 jdk8.tar.gz
文件到 docker-demo
这个目录
- 编写 Dockerfile
在 docker-demo
这个目录下,编写一个 Dockerfile
文件,其内容如下:
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local
# 拷贝 JDK 和 Java 项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 安装 JDK
RUN cd $JAVA_DIR \
&& tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 暴露端口
EXPOSE 8090
# 入口,Java 项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar
- 构建和运行 Docker 镜像
在 docker-demo
目录下,执行以下命令构建 Docker 镜像:
docker build -t java-app:1.0 .
运行这个镜像:
docker run -d -p 8090:8090 --name java-app java-app:1.0
最后在浏览器中访问: http://宿主机IP:8090/hello/count
:
通过这个示例,我们成功地基于 Ubuntu 镜像构建了一个包含 Java 项目的镜像,并运行了一个容器。这展示了 Dockerfile 的使用以及如何在容器中运行 Java 应用程序。
在示例一中,我们使用了 Ubuntu 作为基础镜像。这一示例中,我们将使用 java:8-alpine
作为基础镜像,这是一个更轻量级的镜像,适用于精简容器体积的场景。
什么是
java:8-alpine
java:8-alpine
是一个基于 Alpine Linux 发行版的 Docker 镜像,专门用于运行 Java 应用程序。让我们拆解这个标签的含义:
java
:这表示这个镜像是为 Java 应用程序准备的。8
:这表示 Java 版本,具体是 Java 8。alpine
:这表示基础操作系统是 Alpine Linux。Alpine Linux 是一个轻量级的 Linux 发行版,以小巧、简单而闻名。Alpine Linux 与传统的 Linux 发行版相比,更注重精简和安全。它的包管理系统采用 apk
,而不是像 Ubuntu 和 CentOS 那样使用 apt
或 yum
。由于精简的设计,Alpine Linux 提供了更小的镜像体积,这对于容器化应用来说非常重要。
因此,java:8-alpine
镜像是一个非常适合运行 Java 应用程序的轻量级选择。
- 修改 Dockerfile
在 docker-demo
目录下,修改 Dockerfile
文件如下:
# 指定基础镜像
FROM java:8-alpine
# 拷贝 Java 项目的包
COPY ./docker-demo.jar /tmp/app.jar
# 暴露端口
EXPOSE 8090
# 入口,Java 项目的启动命令
CMD ["java", "-jar", "/tmp/app.jar"]
在 docker-demo
目录下,执行以下命令重新构建 Docker 镜像:
docker build -t java-app:2.0 .
运行这个镜像:
docker run -d -p 8090:8090 --name java-app-alpine java-app:2.0
最后在浏览器中访问: http://宿主机IP:8090/hello/count
:
通过这个示例,我们成功地使用了 java:8-alpine
作为基础镜像,实现了相同的 Java 项目运行。这样的修改不仅提高了容器的轻量级,同时也减小了镜像体积。