玩转Docker(一):基本概念
容器技术是继大数据和云计算之后又一炙手可热的技术,而且未来相当一段时间内都会非常流行。
本文将对其基本概念和基本使用做出介绍。包括容器生态系统、容器的原理、怎样运行第一个容器、容器技术的概念与实践、Docker镜像等等
目录
一. 鸟瞰容器生态系统
1. 容器生态系统包含哪些不同层次的技术?
2. 先了解下Docker
3. 容器、镜像、镜像仓库
4. Docker容器与虚拟机技术的区别和联系
二. 运行第一个容器
三. 容器技术
1. What - 什么是容器?
2. Why - 为什么需要容器?
3. How - 容器是如何工作的
Docker架构
Docker服务器:Docker Daemon
Docker客户端:Docker CLI
Docker镜像:Image
Docker容器:Container
Registry:存放Docker镜像的仓库
4. 小结
四. Docker镜像
1. 镜像的内部结构
hello-world -- 最小的镜像
base镜像
支持运行多种LinuxOS
2. 镜像的分层结构
3. 构建镜像
docker commit
Dockerfile
RUN vs CMD vs ENTRYPOINT
一. 鸟瞰容器生态系统
1. 容器生态系统包含哪些不同层次的技术?
容器生态系统是基于Docker等各种容器的生态系统,包含的技术层次
容器生态系统包含核心技术、平台技术和支持技术。
简而言之:
- 核心技术:能够让 Container 在 host 上运行的那些技术。解决的是容器自身怎样运行。
- 平台技术:关注一组容器如何组织运行,管理这组容器的生命周期。
- 容器支持技术:支持基于容器的基础设施。例如,容器网络、服务发现、监控、数据管理、日志管理、安全性等等
2. 先了解下Docker
Docker是一种开源的容器化平台,旨在简化应用程序的开发、部署和运行过程。提供了一种轻量级、可移植和自包含的容器化环境,使开发人员能够在不同计算机上以一致的方式构建、打包和分发应用程序
3. 容器、镜像、镜像仓库
-
容器(Container):容器是Docker中运行应用程序的运行时实例。它是一个轻量级、可执行的软件包,包含了运行某个应用程序所需的所有内容,包括代码、运行时、系统工具、系统库和设置等。容器基于镜像创建,是镜像的运行实例。容器可以处于以下几种状态:
- 运行中:容器正在运行应用程序
- 已停止:容器已经停止运行,但仍然存在于系统中,可以随时重新启动。
- 已删除:容器被删除后,其所有数据和状态都会被清除。
-
镜像(Image):镜像是容器的模板,是只读的。它包含了容器运行所需的文件系统和应用程序的初始状态。镜像是由一系列的分层文件系统组成的,每一层都包含了特定的修改或更新。
-
镜像仓库(Image Registry):镜像仓库是用于存储和分发 Docker 镜像的地方。最常用的公共镜像仓库是 Docker Hub,上面有大量的官方和社区共享的镜像。此外,还可以搭建私有的镜像仓库,用于存放自己的镜像。
-
Dockerfile:Dockerfile 是一种文本文件,用于定义 Docker 镜像的构建过程。它包含了一系列的指令,用于指定基础镜像、安装软件、拷贝文件、配置环境等。通过 Dockerfile,可以自动化地构建镜像,确保镜像的一致性和可重复性。
4. Docker容器与虚拟机技术的区别和联系
Docker容器和虚拟机都是用于隔离和运行应用程序的技术,但它们在实现方式、性能、资源占用、启动速度等方面存在显著差异。以下是它们的主要区别:
- Docker容器:容器是一种轻量级的隔离运行环境,基于宿主机的操作系统内核,共享内核但拥有独立的文件系统、网络接口和进程空间。容器启动快(通常几秒内完成),资源占用低,性能接近物理机,适合快速部署和运行应用程序,尤其适用于微服务架构和开发测试环境。
- 虚拟机:虚拟机通过虚拟化技术创建一个完整的虚拟计算机环境,运行独立的操作系统和应用程序。它提供强隔离性,适合运行多个不同操作系统或需要高度安全隔离的场景。虚拟机启动慢(通常几分钟),资源占用高,性能损耗较大,但可移植性强,适合长期运行且对隔离性要求高的应用。
5. 运行第一个容器
首先,请安装Docker并配置Docker的apt源。
- 配置Docker的APT源主要是为了确保能够从官方或可信的源中安装和更新Docker软件包,同时也能解决一些常见的问题,比如版本兼容性、软件更新以及网络访问速度等。
- 由于Docker Hub的服务在国外,下载镜像比较慢,最好配置成为免费的国内镜像服务。
环境就绪,马上运行第一个容器,执行命令:
docker run -d -p 80:80 httpd
结果如图所示:
其过程可以简单描述为:
1. 从Docker Hub下载httpd镜像
2. 启动httpd容器,并将容器的80端口映射到host的80端口
3. 下面可以通过浏览器验证容器是否正常工作。在浏览器中输入:http://[your ubuntu host ip]/
结果如图所示:
二. 容器技术
容器技术,需要搞清楚 What、why 和 How三个方面:什么是容器、为什么使用容器、容器是如何工作的。其中容器是怎样工作的,是容器核心知识的最主要部分。
1. What - 什么是容器?
容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。
容器与虚拟机
谈到容器,就不得不将它与虚拟机进行对比,因为两者都是为应用提供封装和隔离。
- 容器由两部分构成:应用程序本身、及其依赖(比如应用程序需要的库或者其他软件容器在Host操作系统的用户空间中运行,与操作系统的气压进程隔离,这一点显著区别于虚拟机)。
- 传统的虚拟化技术:目标是创建完整的虚拟机。为了运行应用,除了部署应用本及其依赖,还得安装整个操作系统。
由于所有容器共享一个host os,这使得容器在体积上要比虚拟机小很多。另外,启动容器不需要启动整个操作系统,所以容器部署和启动更快、开销更小也更容易迁移。
2. Why - 为什么需要容器?
为什么需要容器,容器到底解决了什么问题?简要的答案是,容器使软件具备了超强的移植能力。
就像集装箱解决了货物运输过程中,不同种类的货物相互影响、干扰的难题。
任何货物,不论是钢琴和保时捷,都被放到各自的集装箱中。集装箱在整个运输过程中都是密封的,只有到达最终目的地才会被打开。集装箱被誉为运输界与世界贸易最重要的发明。(容器和集装箱的英文单词都是:Container)
Docker将集装箱思想用到软件打包上,为代码提供了一个基于容器的标准化运输系统。
Docker可以将任何应用以及依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。
3. How - 容器是如何工作的
Docker架构
Docker的核心组件包括:
- Docker客户端:Client
- Docker服务器:Docker daemon
- Docker镜像:Image
- Registry
- Docker容器:Container
Docker架构如图所示
Docker采用的是Client / Server架构。客户端向服务器发送请求,服务器请求构建、运行和分发容器。客户端和服务器可以运行在同一个Host上,客户端也可以通过socket或REST API与远程服务器通信。
Docker服务器:Docker Daemon
Docker 服务器是容器管理的核心,负责实际的容器生命周期管理和资源分配。
Docker服务器是Docker的后台服务进程,通常定义为Docker守护进程。它负责管理Docker的生命周期,包括创建、运行、停止、删除容器等操作。
功能:
- 容器管理:接收来自客户端的指令,执行容器的创建、启动、停止、删除等操作。
- 镜像管理:管理Docker镜像的拉取、存储和推送
- 网络管理:配置容器的网络环境,包括虚拟网络、端口映射等。
- 存储管理:管理容器的存储卷,支持数据持久化。
- 资源隔离:通过 Linux 内核的命名空间(Namespaces)和控制组(Cgroups)技术,为容器提供隔离的运行环境。
运行方式:Docker服务器通常在后台运行,监听来自客户端的请求,并执行相应的操作。
Docker客户端:Docker CLI
Docker 客户端是用户与 Docker 服务器之间的桥梁,提供用户友好的交互方式,方便用户发送命令和管理容器。最常用的Docker客户端是docker命令。通过docker我们可以方便地在Host上构建和运行容器。
- Docker客户端是用户与Docker服务器交互的工具,通常是一个命令行界面(CLI),用户通过它发送命令来控制Docker服务器。
功能:
- 命令执行:用户通过命令行输入指令,如
docker run
、docker build
、docker stop
等,将这些指令发送给 Docker 服务器。 - 交互界面:提供用户友好的交互方式,方便用户管理容器和镜像。
- 配置管理:允许用户配置 Docker 的运行参数,如网络设置、存储驱动等。
运行方式:Docker 客户端通常运行在用户的本地机器上,通过网络(默认是本地套接字)与 Docker 服务器通信。
Docker镜像:Image
可将Docker镜像看成只读模板,通过它可以创建Docker容器。
镜像有多种生成方法:
- 从无到有开始创建镜像
- 下载并使用别人创建好的现成的镜像
- 在现有镜像上创建新的镜像
可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称为Dockerfile,通过执行docker build <docker-file> 命令可以构建出Docker镜像。
Docker容器:Container
Docker容器就是Docker镜像的运行实例。
用户可以通过CLI(Docker)或是API启动、停止、移动或删除容器。可以这么认为:对于应用软件,镜像是软件生命周期的构建和打包阶段,而容器则是启动和运行阶段。
Registry:存放Docker镜像的仓库
Registry是存放Docker镜像的仓库,Registry分为私有和公有两种。
Docker Hub(https://hub.docker.com/)是默认的Registry,由Docker公司维护,上面有数以万计的镜像,用户可以自由下载和使用。
出于对速度或安全的考虑,用户也可以创建自己的私有Registry。
- docker pull 命令可以从Registry下载镜像。
- docker run 命令则是先下载镜像(如果本地没有),然后再启动容器。
还记得我们运行的第一个容器吗?现在通过它来体会一下Docker各个组件是如何协作的。容器启动过程如下:
1. Docker客户端执行docker run命令
2. Docker Daemon发现本地没有httpd镜像
3. daemon从Docker Hub下载镜像
4. 下载完成,镜像httpd被保存到本地
5. Docker daemon启动容器。
docker images已经可以查看到httpd已经下载到本地
docker ps 或者 docker container ls 显示容器正在运行。
4. 小结
Docker借鉴了集装箱的概念。标准集装箱将货物运往世界各地,Docker将这个模型运用到自己的设计哲学中。唯一不同的是:集装箱运输货物,Docker运输软件。
每个容器都有一个软件镜像,相当于集装箱中的货物。容器可以被创建、启动、关闭和销毁。和集装箱一样,Docker在执行这些操作时,并不关心容器里面到底装的什么,它不管里面是Web Server,还是Data-base。用户不需要关心容器最终在哪里运行,因为在哪里都可以运行
开发人员可以在笔记本上构建镜像并上传到Registry,然后QA人员将镜像下载到物理或虚拟机做测试,最终容器会部署到生产环境。
使用Docker以及容器技术,我们可以快速的构建一个应用服务器、一个消息中间件、一个数据库、一个持续集成的环境。因为Docker Hub上有我们能想到的几乎所有的镜像。
三. Docker镜像
镜像是Docker容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。
本章内容安排如下:首先通过研究几个典型的镜像,分析镜像的内部结构;然后学习如何构建自己的镜像;最后介绍怎样管理和分发镜像。
1. 镜像的内部结构
为什么我们要讨论镜像的内部结构?如果只是使用镜像,当然不需要了解,直接通过Docker命令下载和运行就可以了。
但如果我们想构建自己的镜像,或者想理解Docker为什么是轻量级的,就非常有必要学习这部分知识了。
我们从一个最小的镜像开始学习。
hello-world -- 最小的镜像
hello-world是Docker官方提供的一个镜像,通常用来检验Docker是否安装成功。我们先通过docker pull 从Docker Hub下载它,如图所示:
用 docker images 查看镜像的信息,如图所示:
hello-world竟然还不到2kb,通过docker run运行,如图所示:
其实我们更关心 hello-world 镜像包含了哪些内容。
Dockerfile是镜像的描述文件,定义了如何构建Docker镜像。Dockerfile的语法简洁且可读性强,后面我们会讨论如何编写Dockerfile。
hello-world 的 Dockerfile内容如下图所示:
只有短短三条指令。
(1)From scratch镜像是白手起家,从0开始构建
(2)COPY hello/ 将文件 “hello”复制到镜像的根目录
(3)CMD ["/hello"] 容器启动时,执行 /hello
镜像hello-world中就只有一个可执行文件 “hello”,其功能就是打印出 “Hello from Docker...”等信息。
/hello 就是文件系统的全部内容,连最基本的 /bin /usr /lib /dev 都没有
hello-world虽然是一个完整的镜像,但它并没有什么实际用途。通常来说,我们希望镜像能够提供一个基本的操作系统环境,用户可以根据需要安装和配置软件。
这样的镜像我们称作 base镜像。
base镜像
base镜像有两层含义:
- 不依赖于其他镜像,从scratch构建
- 其他镜像可以以之为基础进行扩展
所以,能称作base镜像的通常都是各种Linux发行版的Docker镜像,比如Ubuntu、Debian、CentOS等。
我们以CentOS为基础为例考察base镜像包含哪些内容。
下载镜像:
docker pull centos
查看镜像信息,如下图:
镜像大小不到200MB
等一下!
一个CentOS才200MB?
平时我们安装一个CentOS至少都有几个GB,怎么可能才200MB!
相信这是几乎所有 Docker 初学者都会有的疑问,包括我自己。下面我们来解释这个问题。
Linux操作系统由内核空间和用户空间组成,如下图:
1. rootfs
内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉。
用户空间的文件系统是rootfs,包含我们熟悉的 /dev /proc /bin等目录
对于 base镜像 来说,底层直接用 Host 的 kernel,自己只需要提供rootfs就行了。
- 而对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他的Linux发行版,CentOS的rootfs已经算臃肿的了,alpine还不到10MB
- 我们平时还会安装的CentOS除了rootfs之外,还会选装很多软件、服务、图形桌面等等,需要好几个GB就不足为奇了。
2. base镜像提供的是最小安装的Linux发行版
CentOS镜像的Dockerfile的内容如下图所示:
第二行ADD指令添加到镜像的 tar 包就是 CentOS 7 的rootfs,在制作镜像时,这个tar包会自动解压到 / 目录下,生成 /dev、/proc、/bin等目录。
支持运行多种LinuxOS
不同Linux发行版的区别主要就是rootfs,所以Docker可以同时支持多种Linux镜像,模拟出多种操作系统环境。
上图Debian和BusyBox(一种嵌入式Linux)上层提供各自的rootfs,底层共用Docker Host的kernel
2. 镜像的分层结构
Docker支持通过扩展现有镜像,创建新的镜像。
实际上,Docker Hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的。比如我们构建一个新的镜像,Dockerfile 如下图所示:
(1)新镜像不再是从scratch开始,而是直接在Debian base镜像上创建
(2)安装 emacs 编辑器
(3)安装 Apache2
(4)容器启动时运行 bash
构建过程中如下图:
可以看到,新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
为什么Docker镜像要采用这种分层结构呢?
最大的一个好处就是:共享资源。
3. 构建镜像
对于Docker用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成Docker官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。
使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用官方的镜像,因为Docker工程师更知道如何更好地在容器中运行软件。
当然,某些情况下我们也不得不自己构建镜像,比如:
(1)找不到现成的镜像,比如自己开发的应用程序。
(2)需要在镜像中加入特定的功能,比如官方镜像几乎都不提供ssh
所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。
Docker提供了两种构建镜像的方法:docker commit命令与Dockerfile构建文件。
docker commit
docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:
- 运行容器
- 修改容器
- 将容器保存为新的镜像
举个例子:在Ubuntu base镜像中安装vi并保存为新镜像。
(1)运行容器
如图所示:
-it的作用是以交互模式进入容器,并打开终端。
(2)安装vi
确认vi没有安装,如下图所示:
安装vi,如下图所示:
(3)保存为新镜像
在新窗口中查看当前运行的容器,如图所示:
silly_goldberg是Docker为我们容器随机分配的名字。
执行 docker commit 命令将容器保存为镜像,如图所示:
新镜像命名为ubuntu-with-vi
查看新镜像的属性,如图所示:
从size上看到镜像因为安装了软件而变大了。
从新镜像启动容器,验证 vi 已经可以使用,如图所示:
以上演示了如何用 docker commit创建新镜像。然而,Docker并不建议用户通过这种方式构建镜像。原因如下:
(1)这是一种手动创建镜像的方式,容易出错,效率低且可重复性若。比如要在 debian base镜像中也加入vi,还得重复前面所有的步骤。
(2)更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。
既然 docker commit不是推荐的方法,我们为什么还要花时间学习呢?原因是,即便是用Dockerfile(推荐方法)构建镜像,底层也是docker commit一层一层构建新镜像的。学习docker commit 能够帮助我们更加深入地理解构建过程和镜像的分层结构。
Dockerfile
Dockerfile是一个文本文件,记录了镜像够简单的所有步骤。
1. 第一个Dockerfile
用 Dockerfile 创建上节的 ubuntu-with-vi,其内容如图所示:
下面我们运行 docker build 命令构建镜像并详细分析每个细节。
root@ubuntu:~# pwd ①/rootroot@ubuntu:~# ls ②Dockerfileroot@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile . ③Sending build context to Docker daemon 32.26 kB ④Step 1 : FROM ubuntu ⑤---> f753707788c5Step 2 : RUN apt-get update && apt-get install -y vim ⑥---> Running in 9f4d4166f7e3 ⑦......Setting up vim (2:7.4.1689-3ubuntu1.1) ...---> 35ca89798937 ⑧Removing intermediate container 9f4d4166f7e3 ⑨Successfully built 35ca89798937 ⑩root@ubuntu:~#
① 当前目录为 /root。
② Dockerfile准备就绪。
③ 运行docker build命令,-t将新镜像命名为ubuntu-with-vi-dockerfile,命令末尾的.指明build context为当前目录。Docker默认会从build context中查找Dockerfile文件,我们也可以通过-f参数指定Dockerfile的位置。
④ 从这步开始就是镜像真正的构建过程。
首先Docker将build context中的所有文件发送给Docker daemon。build context为镜像构建提供所需要的文件或目录。 Dockerfile中的ADD、COPY等命令可以将build context中的文件添加到镜像。此例中,build context为当前目录 /root,该目录下的所有文件和子目录都会被发送给Docker daemon。 所以,使用build context就得小心了,不要将多余文件放到build context,特别不要把 /、/usr作为build context,否则构建过程会相当缓慢甚至失败。
⑤ Step 1:执行FROM,将Ubuntu作为base镜像。 Ubuntu镜像ID为f753707788c5。
⑥ Step 2:执行RUN,安装vim,具体步骤为 ⑦ ⑧ ⑨。
⑦ 启动ID为9f4d4166f7e3的临时容器,在容器中通过apt-get安装vim。
⑧ 安装成功后,将容器保存为镜像,其ID为35ca89798937。 这一步底层使用的是类似docker commit的命令。
⑨ 删除临时容器9f4d4166f7e3。
⑩ 镜像构建成功。
通过docker images查看镜像信息,如图3-21所示。 [插图] 图3-21 镜像ID为35ca89798937,与构建时的输出一致。 在上面的构建过程中,我们要特别注意指令RUN的执行过程 ⑦ ⑧ ⑨。Docker会在启动的临时容器中执行操作,并通过commit保存为新的镜像。
2. 查看镜像的分层结构
ubuntu-with-vi-dockerfile 是通过在base镜像的顶部增加一个新的镜像层而得到的,如图所示:
这个新镜像层的内容由 RUN apt-get update && apt-get in stall -y vim 生成。这一点我们可以通过docker history命令验证,如图所示:
docker history会显示镜像的构建历史,也就是Dockerfile的执行过程。
ubuntu-with-vi-dockerfile 与 Ubuntu 镜像相比,确实只是多了顶部的一层35ca89798937,由apt-get命令创建,大小为97.07MB。docker history向我们展示了镜像的分层结构,每一层由上至下排列。
注:missing表示无法获取IM-AGE ID,通常从 Docker Hub 下载的镜像会有这个问题。
3. 镜像的缓存特征
我们接下来看Docker镜像的缓存特征。
Docker会缓存已有镜像的镜像层,构建新镜像时,如果某镜像直接存在,就直接使用,无需重新创建。
例如,如果在Dockerfile中添加一点新内容,往镜像中复制一个文件:
(1)确保 testfile 已存在
(2)由于之前已经运行过相同的 RUN 命令,这次直接使用缓存中的镜像层 35ca89798937
(3)执行 COPY 命令
其过程是启动临时容器,复制 testfile,提交新的镜像层 8d02784a78f4,删除临时容器。
在ubuntu-with-vi-dockerfile 镜像上直接添加一层就得到了新的镜像 ubuntu-with-vi-docker-file-2,如图所示:
如果我们希望在构建镜像时不使用缓存,可以在 docker build 命令中加上 no-cache 参数。
Dockerfile每一个指令就会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。
也就是说,如果我们改变 Dockerfile 的执行顺序,或者修改或者添加指令,都会使缓存失效。举例说明:
- 如果交换前面 RUN 和 COPY 的顺序,如图所示:
- 虽然在逻辑上这种改动对镜像的内容没有影响,但由于分层的结构特征,Docker必须重建受影响的镜像层。
- 从执行过程可以看到,生成了新的镜像层,缓存已经失效。
除了构建时使用缓存,Docker在下载镜像时也会使用。
4. 调试Dockerfile
总结一下通过 Dockerfile 构建镜像的过程:
(1)从base镜像运行一个容器
(2)执行一条指令,对容器做修改
(3)执行类似docker commit的操作,生成一个新的镜像
(4)Docker再基于刚刚提交的镜像运行一个新容器
(5)重复2~~4步,直到Dockerfile中的所有指令执行完毕
5. Dockerfile 常用指令
是时候系统学习Dockerfile了
- FROM:指定base镜像
- MAINTAINER:设置镜像作者,可以是任意字符串
- COPY:
- 将文件从build context复制到镜像
- COPY支持两种形式:COPY src dest 与 COPY ["src", "dest"]
- 注意,src只能指定 build context 中的文件或目录
- ADD:
- 与COPY类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar、zip、tgz、xz等),文件会被自动解压到dest
- ENV:
- 设置环境变量,环境变量可以被后面的指令使用。例如:
-
ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION
-
EXPOSE:
-
指定容器中的进程会监听某一个端口,Docker可以将该端口暴露出来。
-
-
VOLUMN:
-
将文件或者目录声明为volume
-
-
WORKDIR:
-
为后面的RUN、CMD、ENTRY-POINT、ADD或COPY指令设置镜像中的当前工作目录
-
-
RUN
-
在容器中执行指定的命令
-
-
CMD
-
容器启动时运行指定的命令
-
Dockerfile可以有多个CMD指令,但只有最后一个生效。CMD可以被 docker run 之后的参数替换。
-
-
ENTRYPOINT
-
设置容器启动时运行的命令。
-
Dockerfile中可以有多个ENTRYPOINT指令,但只有最后一个生效。CMD 或 docker run之后的参数会被当做参数传递给 ENRTYPOINT。
-
这是一个比较全面的Dockerfile(注:Dockerfile支持以 “#” 开头的注释)
构建镜像,如下图:
(1)构建前确保build context中存在需要的文件
(2)依次执行Dockerfile指令,完成构建
(3)运行容器,验证镜像内容,如下图
1. 进入容器,当前目录即为WORKDIR
如果WORKDIR不存在,Docker会自动帮我们创建
2. WORKDIR中保存了我们希望的文件和目录
目录bunch:由ADD指令从build context复制的归档文件bunch.tar.gz,已经自动解压。 文件tmpfile1:由RUN指令创建。 文件tmpfile2:由COPY指令从build context复制。
3. ENV指令定义的环境变量已经生效。
RUN vs CMD vs ENTRYPOINT
RUN、CMD和ENTRYPONIT这三个Dockerfile指令看上去很类似,很容易混淆。
简单地说:
(1)RUN:执行命令并创建新的镜像层,RUN经常用于安装软件包
(2)CMD:设置容器启动后默认执行的命令及其参数,但CMD能够被 docker run 后面接的命令行替换
(3)ENTRYPOINT:配置容器启动时运行的命令
最佳实践:
1. 使用RUN命令安装应用和软件包,构建镜像
2. 如果docker镜像的用途是运行应用程序或服务,比如运行一个MySQL,应该使用Exec格式的ENTRYPOINT指令。CMD可为ENTRYPONIT提供额外的默认参数,同时可以利用 docker run 命令行替换默认参数,同时可以利用 docker run 命令行替换默认参数。
3. 如果想为容器设置默认的启动命令,可使用CMD指令,用户可在 docker run 命令中替换此默认命令。
4. 小结
本章我们学习了Docker镜像。首先讨论了镜像的分层结构,然后学习了如何构建镜像,最后实践使用Docker Hub和本地registry。
下面是镜像的常用操作子命令:
- images:显示镜像列表。
- history:显示镜像构建历史。
- commit:从容器创建新镜像。
- build:从Dockerfile构建镜像。
- tag:给镜像打tag。
- pull:从registry下载镜像。
- push:将镜像上传到registry。
- rmi:删除Docker host中的镜像。
- search:搜索Docker Hub中的镜像。
以上是 docker 技术的基本概念,其余知识明日继续连载
Good night~~
-- 2025年5月2日
相关文章:
玩转Docker(一):基本概念
容器技术是继大数据和云计算之后又一炙手可热的技术,而且未来相当一段时间内都会非常流行。 本文将对其基本概念和基本使用做出介绍。包括容器生态系统、容器的原理、怎样运行第一个容器、容器技术的概念与实践、Docker镜像等等 目录 一. 鸟瞰容器生态系统 1. 容器…...
Linux系统安装方式+适合初学者的发行版本
Linux系统安装方式适合初学者发行版—目录 一、Linux系统的安装方式1. 物理机直接安装2. 虚拟机安装3. 双系统安装4. Live USB试用5. 云服务器安装 二、适合初学者的Linux发行版1. Ubuntu2. Linux Mint3. Zorin OS4. Pop!_OS5. Elementary OS6. Fedora7. Manjaro 三、选择建议场…...
开启 Spring AI 之旅:从入门到实战
开启 Spring AI 之旅:从入门到实战 引言 在当今人工智能飞速发展的时代,Spring AI 为开发者们提供了一个强大而便捷的工具,用于在 Spring 生态系统中构建 AI 应用程序。本文将为你提供如何开始使用 Spring AI 的详细指南,帮助你…...
python数据分析(七):Pandas 数据变形与重塑
Pandas 数据变形与重塑全面指南 1. 引言 在数据分析过程中,我们经常需要将数据从一种结构转换为另一种结构,以适应不同的分析需求。Pandas 提供了丰富的数据变形与重塑功能,包括旋转(pivot)、堆叠(stack)、融合(melt)等多种操作。本文将详细…...
SX24C01.UG-PXI程控电阻桥板卡
PXI程控电阻桥板卡 概述 简介 程控电阻桥板卡采用4 个可程控精密调节的电阻臂组成桥式电路,通过计算机PXI总线控制继电器通断进行电阻调节;可根据具体情况,方便地选择不同桥路的连接;程控电阻桥板卡支持“1/4 桥”、“半桥”和…...
Python项目源码69:一键解析+csv保存通达信日线数据3.0
Python项目源码39:学生积分管理系统1.0(命令行界面Json) Python项目源码38:模拟炒股系统2.0(tkinterJson) Python项目源码35:音乐播放器2.0(Tkintermutagen) Python项…...
Conda 与 Spyder 环境管理
前言 作为 Python 科学计算领域的黄金搭档,Anaconda 和 Spyder 为研究人员和数据分析师提供了强大的工作环境。本文将详细介绍如何使用 Conda 管理 Python 环境,并在 Spyder IDE 中灵活切换这些环境,助你打造高效的 Python 开发工作流。 一…...
头皮理疗预约小程序开发实战指南
生活服务类小程序开发正成为互联网创业的热点领域,头皮理疗预约小程序作为其中的细分品类,具有广阔的市场前景和用户需求。基于微信小程序原生开发或uniapp框架,结合Java后端和MySQL数据库,可构建一个功能完善、性能稳定且易于维护的头皮理疗预约平台。本文将从零开始,详细…...
cPanel 的 Let’s Encrypt™ 插件
在 cPanel & WHM 中,推出了一个名为 AutoSSL 的功能。可能有些朋友还不了解 AutoSSL,它是一个能够自动为您的网站申请和安装免费 SSL 证书的工具,这些证书由 Comodo 签发,保证网站的安全性。 AutoSSL 与 Let’s Encrypt Let’…...
《Android 应用开发基础教程》——第十一章:Android 中的图片加载与缓存(Glide 使用详解)
目录 第十一章:Android 中的图片加载与缓存(Glide 使用详解) 🔹 11.1 Glide 简介 🔸 11.2 添加 Glide 依赖 🔸 11.3 基本用法 ✦ 加载网络图片到 ImageView: ✦ 加载本地资源 / 文件 / UR…...
MySQL 中的游标(Cursor)
一、游标的作用 逐行处理数据:当需要对查询结果集中的每一行进行特定操作(如计算、条件判断、调用其他过程)时使用。替代集合操作:在无法通过单一 SQL 语句完成复杂逻辑时,游标提供逐行处理的能力。…...
【嵌入式Linux】基于ARM-Linux的zero2平台的智慧楼宇管理系统项目
目录 1. 需求及项目准备(此项目对于虚拟机和香橙派的配置基于上一个垃圾分类项目,如初次开发,两个平台的环境变量,阿里云接入,摄像头配置可参考垃圾分类项目)1.1 系统框图1.2 硬件接线1.3 语音模块配置1.4 …...
记忆翻牌游戏:认知科学与状态机的交响曲
目录 记忆翻牌游戏:认知科学与状态机的交响曲引言第一章 网格空间拓扑学1.1 自适应网格算法1.2 卡片排布原理 第二章 状态机设计2.1 状态跃迁矩阵2.2 时空关联模型 第三章 记忆强化机制3.1 认知衰减曲线3.2 注意力热力图 第四章 动画引擎设计4.1 翻牌运动方程4.2 粒…...
【业务领域】InfiniBand协议总结
InfiniBand协议总结 InfiniBand协议是什么?Infiniband产生的原因Mellanox公司介绍及其新闻基于TCP/IP的网络与IB网络的比较IB标准的优势什么是InfiniBand网络什么是InfiniBand架构Mellanox IB卡介绍InfiniBand速率发展介绍InfiniBand网络主要上层协议InfiniBand管理…...
使用Java正则表达式检查字符串是否匹配
在Java开发中,正则表达式(Regular Expression,简称Regex)是处理字符串的强大工具,广泛应用于模式匹配、数据验证和文本处理。Java通过java.util.regex包提供了对正则表达式的支持,包含Pattern和Matcher两个…...
个人健康中枢的多元化AI硬件革新与精准健康路径探析
在医疗信息化领域,个人健康中枢正经历着一场由硬件技术革新驱动的深刻变革。随着可穿戴设备、传感器技术和人工智能算法的快速发展,新一代健康监测硬件能够采集前所未有的多维度生物数据,并通过智能分析提供精准的健康建议。本文将深入探讨构成个人健康中枢的最新硬件技术,…...
Android基础控件用法介绍
Android基础控件用法详解 Android应用开发中,基础控件是构建用户界面的核心元素。本文将详细介绍Android中最常用的基础控件及其用法。 一、TextView(文本显示控件) TextView用于在界面上显示文本信息。 基本用法 <TextViewandroid:id="@+id/textView"andr…...
iO(不可区分混淆)是Web3隐私的圣杯?
1. 引言 iO 是区块链隐私的圣杯吗?本文将探讨: 不可区分混淆(indistinguishability obfuscation, iO)的局限性iO可能带来的变革iO为何重要?iO是否能真正成为可信硬件的替代方案? 区块链隐私面临的最大挑…...
文章三《机器学习基础概念与框架实践》
文章3:机器学习基础概念与框架实践 ——从理论到代码,用Scikit-learn构建你的第一个分类模型 一、机器学习基础理论:三大核心类型 机器学习是人工智能的核心,通过数据让计算机自动学习规律并做出预测或决策。根据学习方式&#…...
中小企业MES系统概要设计
版本:V1.0 日期:2025年5月2日 一、系统架构设计 1.1 整体架构模式 采用分层微服务架构,实现模块解耦与灵活扩展,支持混合云部署: #mermaid-svg-drxS3XaKEg8H8rAJ {font-family:"trebuchet ms",verdana,ari…...
自动化测试项目1 --- 唠嗑星球 [软件测试实战 Java 篇]
目录 项目介绍 项目源码库地址 项目功能测试 1.自动化实施步骤 1.1 编写测试用例 1.2 自动化测试脚本开发 1.2.1 配置相关环境, 添加相关依赖 1.2.2 相关代码编写 2. 自动化功能测试总结 2.1 弹窗的解决相关问题 2.2 断言的使用和说明 2.3 重新登录问题 项目性能…...
c语言 关键字--目录
1.c语言 关键字 2.typedef 关键字 3.volatile 关键字 4.register 关键字 5.const关键字用法 6.extern关键字...
C语言与指针3——基本数据类型
误区补充 char 的 表示范围0-127 signed char 127 unsigned char 0-255enum不常用,但是常见,这里记录一下。 enum Day {Monday 1,//范围是IntTuesday 2,Wednesday 3 }; enum Day d Monday; switch (d) {case Monday:{printf("%d",Monday);…...
[更新完毕]2025五一杯C题五一杯数学建模思路代码文章教学:社交媒体平台用户分析问题
完整内容请看文章最下面的推广群 社交媒体平台用户分析问题 在问题一中为解决博主在特定日期新增关注数的预测问题,本文构建了基于用户历史行为的二分类模型。首先,从用户对博主的观看、点赞、评论、关注等交互行为中提取统计与时序特征,形成…...
使用Vite创建vue3项目
什么是vite Vite 是新一代构建工具,由 Vue 核心团队开发,提供极快的开发体验。 它利用浏览器原生ES模块导入功能,提供了极快的热模块更新(HMR)和开发服务器启动速度。 官网:https://vitejs.cn/vite3-cn/…...
Linux管道识
深入理解管道 (Pipes):连接命令的瑞士军刀 在 Linux 和类 Unix 系统(包括 macOS)的命令行世界里,管道(Pipe)是一个极其强大且基础的概念。它允许你将一个命令的输出直接作为另一个命令的输入,像…...
LabVIEW 中VI Server导出 VI 配置
该 LabVIEW VI 展示了在 VI Server 中配置和执行 Exported VIs 的过程,实现对服务器端导出 VI 的远程调用与操作。 具体过程及模块说明 前期配置:需确保在 LabVIEW 的 “Tools> Options > VI Server > Protocols” 路径下,启用 …...
map和set的遗留 + AVL树(1):
在讲解新的东西之前,我们把上节遗留的问题说一下: 遗留问题: 首先,我们的最上面的代码是一个隐式类型转换,我们插入了一对数据。 我们说了,我们的方括号的底层是insert,当我们调用operator的[…...
Java学习手册:Spring Security 安全框架
一、Spring Security 简介 Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,用于保护 Java 应用程序,尤其是基于 Spring 的应用。它构建在 Spring 框架之上,能够轻松地集成到基于 Spring 的应用程序中,包括…...
pip 常用命令及配置
一、python -m pip install 和 pip install 的区别 在讲解 pip 的命令之前,我们有必要了解一下 python -m pip install 和 pip install 的区别,以便于我们在不同的场景使用不同的方式。 python -m pip install 命令使用 python 可执行文件将 pip 模块作…...
C++_STL
C 标准模板库(Standard Template Library,STL)是一套功能强大的 C 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。 STL 的设计基于泛型编程,这意味着使用模板可以编写出独立于任何特定数据类型的…...
[FPGA Video] AXI4-Stream Remapper
Xilinx AXI4-Stream Remapper IP (PG379) 详细介绍 概述 Xilinx LogiCORE™ IP AXI4-Stream Remapper 核是一个专为视频处理设计的模块,用于在不同每时钟像素数(Pixels Per Clock, PPC)要求之间重新映射视频像素。它支持将输入 AXI4-Stream…...
【数据结构】励志大厂版·初阶(复习+刷题):栈与队列
前引:本篇将由小编与大家一起复习 栈 、队列 的知识点,栈、队列的顺序、链式结构各个缺点好处,如何实现、对于一般的增删查找此篇文章一定再详细不过!对代码的注释、何时需要判断、特殊情况,白话文版一解到底ÿ…...
pytest——参数化
之前有说过,通过pytest测试框架标记参数化功能可以实现数据驱动测试。数据驱动测试使用的文件主要有以下类型: txt 文件 csv 文件excel 文件json 文件yaml 文件.... 本文主要讲的就是以上几种文件类型的读取和使用 一.txt 文件读取使用 首先创建一个 …...
第7篇:RESTful API设计与安全防护
在前后端分离架构中,RESTful API是系统交互的核心通道。本文将从接口规范设计到安全防护,全面讲解如何在EggJS中构建安全、规范、易用的API系统,并提供完整的解决方案和最佳实践。 一、标准化API接口规范设计 1. RESTful设计原则 核心要素&…...
CSS 架构与命名规范
CSS 架构与命名规范:BEM、SMACSS 与 OOCSS 实战 引言 在前端开发中,随着项目规模的扩大,CSS 代码往往会变得难以维护和扩展。无组织的样式表会导致命名冲突、权重覆盖问题和样式继承混乱,这些问题在团队协作的大型项目中尤为明显…...
实验二 软件白盒测试
实验二 软件白盒测试 某工资计算程序功能如下:若雇员月工作小时超过40小时,则超过部分按原小时工资的1.5倍的加班工资来计算。若雇员月工作小时超过50小时,则超过50的部分按原小时工资的3倍的加班工资来计算,而40到50小时的工资仍…...
【数据结构】String字符串的存储
目录 一、存储结构 1.字符串常量池 2.字符串哈希表 2.1结构 2.2基础存储单位 2.2.1键对象 2.2.2值对象 二、存储过程 1.搜索 2.创建 三、存储位置 四、存储操作 1.new新建 2.intern入池 这是String类的详解:String类变量 一、存储结构 1.字符串常量池…...
LLMs Tokenizer Byte-Pair Encoding(BPE)
1 Byte-Pair Encoding(BPE) 如何构建词典? 准备足够的训练语料;以及期望的词表大小;将单词拆分为字符粒度(字粒度),并在末尾添加后缀“”,统计单词频率合并方式:统计每一个连续/相邻字节对的出现频率,将最高频的连续字…...
npm,yarn,pnpm,cnpm,nvm,npx包管理器常用命令
前端比较主流的包管理器主要有三个npm,yarn,pnpm 多层级依赖,通常发生在依赖之间存在复杂的版本要求时 包 A 依赖于包 B1.0.0 包 B 依赖于包 C2.0.0 另一个包 D 也依赖于 C3.0.0 一、NPM (Node Package Manager) https://www.npmjs.cn/…...
使用mybatis实例类和MySQL表的字段不一致怎么办
在 MyBatis 中,当 Java 实体类的属性名与数据库表的字段名不一致时,会导致查询结果无法正确映射。以下是几种常见解决方案及代码示例: 1. 使用 resultMap 显式映射(推荐) 场景:字段名与属性名差异较大&…...
阿里发布新一代通义千问 Qwen3模型
近日,阿里巴巴发布了新一代通义千问 Qwen3 模型,一举登顶全球最强开源模型。 这是国内首个“混合推理模型”,将“快思考”与“慢思考”集成进同一个模型,大大节省算力消耗。 旗舰模型 Qwen3-235B-A22B 在代码、数学、通用能力等…...
React pros比较机制
将 count1作为prop传递给Memoson组件 引用类型情况 虽然list值没有发生变化,但是仍旧重新渲染 解决方法使用useMemo()函数,传递一个空依赖项 // 传递数据为引用类型 比较的是引用 // 使用useMemo函数改写、const list useMemo(()>{return [1,2,3]},[…...
Flowable7.x学习笔记(十七)审批我的待办
前言 前文完成了我的待办的查询功能,本文就在此基础上从源码解读到完成审批任务的功能,审批界面我就先不带表单,直接单纯审批通过,这里需要注意的事,审批的表单其实每个节点都可能需要不同的表单内容,后续要…...
HTTP 状态码详解:用途与含义
HTTP 状态码详解:用途与含义 HTTP 状态码详解:用途与含义1. (2xx)成功类200 OK201 Created204 No Content206 Partial Content 2. (3xx)重定向类301 Moved Permanently302 Found(临时重定向&…...
AI日报 · 2025年05月02日 | 再见GPT-4!OpenAI CEO 确认 GPT-4 已从 ChatGPT 界面正式移除
1、OpenAI CEO 确认 GPT-4 已从 ChatGPT 界面正式移除 在处理 GPT-4o 更新问题的同时,OpenAI CEO Sam Altman 于 5 月 1 日在 X 平台发文,正式确认初代 GPT-4 模型已从 ChatGPT 主用户界面中移除。此举遵循了 OpenAI 此前公布的计划,即在 4 …...
ppt设计美化公司_杰青_长江学者_优青_青年长江学者_万人计划青年拔尖人才答辩ppt模板
WordinPPT / 持续为双一流高校、科研院所、企业等提供PPT制作系统服务。 / 近期PPT美化案例 - 院士增选、科学技术奖、杰青、长江学者特聘教授、校企联聘长江、重点研发、优青、青长、青拔.. 杰青(杰出青年科学基金) 支持已取得突出成果的45岁以下学…...
文章四《深度学习核心概念与框架入门》
文章4:深度学习核心概念与框架入门——从大脑神经元到手写数字识别的奇幻之旅 引言:给大脑装个"GPU加速器"? 想象一下,你的大脑如果能像智能手机的GPU一样快速处理信息会怎样?这正是深度学习的终极目标&…...
HTML5+JavaScript实现连连看游戏之二
HTML5JavaScript实现连连看游戏之二 以前一篇,见 https://blog.csdn.net/cnds123/article/details/144220548 连连看游戏连接规则: 只能连接相同图案(或图标、字符)的方块。 连线路径必须是由直线段组成的,最多可以有…...
2025年- H19-Lc127-48.旋转矩阵(矩阵)---java版
1.题目描述 2.思路 画出矩阵,新的旋转矩阵的列坐标等于原始矩阵的矩阵长度-i-1(也就是减去当前遍历的i),前后对调。然后新的旋转矩阵的横坐标,是原始矩阵的列坐标。 3.代码实现 public class H48 {public void rota…...