专业编程基础技术教程

网站首页 > 基础教程 正文

Docker镜像制作及指令说明

ccvgpt 2025-01-21 15:34:22 基础教程 1 ℃

当我们要在一个linux上运行一个软件,比如要运行一个java应用myapp.jar,这是一个自启动的jar.那么整个配置过程可能是这样的:

1、安装java运行环境jre

Docker镜像制作及指令说明

wget https://download.bell-sw.com/java/21.0.3+12/bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz \

&& tar -xzf bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz \

&& rm bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz

2、配置环境变量

export JAVA_HOME=/usr/lib/jvm/jre-21.0.3

export PATH=$PATH:$JAVA_HOME/bin

3、启动应用

java -jer myapp.jar -Dport=8080

如果有多台机器都要运行java应用,那么我们每台机器都要做上述操作,这样就很麻烦。如果将上述操作打包成镜像,通过虚拟机安装就方便的多。虽然每次不需要上述操作但是每次制作镜像以及每次虚拟机启动耗时特别长,且占用CPU和内存等的资源也大。那么有没有一种轻量级虚拟机,制作镜像和启动都很快,只要输入一条指令回车就可以快速完成?当然有!docker、containerd、Podman、CRI-O、runc等。Docker 是目前最流行和广泛使用的容器引擎之一。它提供了完整的容器生命周期管理,包括容器的创建、运行、停止、删除等,以及容器镜像的管理、容器网络、存储、日志和监控等高级功能。k8s1.20以前的版本使用docker容器运行时,而1.20 之后默认使用container,也支持docker,CRI-O。

docker中两个重要概念是镜像(image)和容器(container)。镜像就是一个二进制文件,和上述的虚拟机镜像类似,区别就是虚拟机镜像只记录了系统中软件安装配置完成时的内容,而docker镜像则是记录了这个配置安装过程中各个关键点的内容。也就是说虚拟机镜像只有一层,而docker镜像是多层的,每个关键点内容都被一个层记录,这些层堆叠起来形成一个完整的镜像,可以想象成积木层。每个层记录的不是全量内容,只是相对前一层的变化内容。容器就是用镜像启动的一个轻量级的虚拟机,它的启动快速,占用资源小。容器开始启动时将镜像中的各层加载到内存中,如果已经加载就不在加载。也就是说如果用这个镜像已经运行了一个容器,如果再运行一个容器时就不会再次加载镜像。还有,不同镜像在制作时可能是用了相同的基础镜像或者相同的层,那么这两个镜像在同一个机器上运行容器时镜像中相同的层在内存中只加载一次。这种共享机制加快了容器启动速度和减少了内存使用。容器启动时使用镜像的层构建了一个文件系统视图指向这些镜像层,相同镜像启动的容器都会创建一个文件系统视图并指向内存中的那份镜像层。容器对这些镜像层是只读的。docker会在容器的文件系统视图之上创建一个可写的容器层,当容器运行时对文件系统中的内容做更改时,就在容器层中创建这个内容的副本进行更改。容器被删除后,容器层也会被删除,原先文件系统中的改动就会丢失。除非这些内容所在的目录在容器启动时被挂载到数据卷或宿主机。

接下来说说docker镜像是怎样创建的。docker镜像的创建关键在于Dockerfile文件的编写和基础镜像的选择。Dockerfile 是用于自动化构建 Docker 镜像的文本文件,它包含了一系列指令,每条指令定义了镜像构建过程中的一个步骤。下面就把上述的配置java应用制作成 docker镜像:

首先将文件myapp.jar复制到dockerfile文件夹下,然后开始编写dockerfile文件

[root@yan dockerfile] vi myapp

FROM alpine:3.15.10

WORKDIR /usr/lib/jvm

ENV LANG=zh_CN.UTF-8

RUN apk add --no-cache \

ttf-dejavu \

fontconfig \

tzdata \

&& \

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \

echo "Asia/Shanghai" > /etc/timezone

RUN wget https://download.bell-sw.com/java/21.0.3+12/bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz \

&& tar -xzf bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz \

&& rm bellsoft-jre21.0.3+12-linux-x64-musl.tar.gz

ENV JAVA_HOME=/usr/lib/jvm/jre-21.0.3

ENV PATH=$PATH:$JAVA_HOME/bin

RUN rm -rf /var/cache/apk/*

RUN mkdir -p /usr/apps

WORKDIR /usr/apps

ADD myapp.jar .

ENTRYPOINT ["java"]

CMD ["-jar","myapp.jar"]

[root@yan dockerfile] :wq

[root@yan dockerfile] docker build -t myapp:1.0.0 . -f myapp

以上就是制作镜像的过程,首先在dockerfile目录下编辑 Dockerfile文件openjre21,编辑完保存。在当前目录下执行指令docker build -t myapp:1.0.0. -f myapp构建。

-t myapp:1.0.0指定构建的镜像名称和标签,冒号前是名称,后面是标签。

. 指定构建上下文的目录。

-f myapp指定要使用的Dockerfile文件名,这个Dockerfile应该位于指定的构建上下文目录中。如果 myapp在 dockerfile/test/下,就应该写成 -f test/myapp

Dockerfile文件myapp的内容就是描述了在一台物理机上运行myapp.jar的配置过程,每一条指令创建了一个镜像层。

以下是 Dockerfile 中一些常用指令及其基本用法:

FROM

用途:指定基础镜像。Dockerfile 必须以 FROM 开头来指定一个基础镜像。

示例:FROM ubuntu:latest

USER

用途:指定容器运行时的用户。

示例:USER nobody

说明:nobody这个用户必须已经存在,如果不存在就先创建 RUN adduser nobody.容器运行后,在容器中进行的操作都是在这个用户下进行的。不指定容器默认使用root用户。这样对安全性不好,因为被攻击获得了你的root用户就获得了整个系统的操作权限。

LABEL

用途:添加元数据到镜像中。

示例:LABEL maintainer="yourname@example.com"

说明:为镜像添加元数据描述镜像,格式是LABEL key=value,有几项元数据就是用几个LABEL指令。这个元数据使用docker inspect指令可以查看。

RUN

用途:执行命令,用于安装软件包、设置环境变量或修改文件系统等。

示例:RUN apt-get update && apt-get install -y nginx

COPY

用途:从构建上下文目录中复制文件或目录到新的一层的镜像内部,构建上下文目录是在宿主机上。

示例:COPY myfile /app

说明:将宿主机上的myfile复制到镜像中指定的位置,指定的位置不存在就创建.如果目标目录不存在,Docker 会创建它,并且默认权限为 0755。如果目标文件不存在,Docker 会创建它,并且默认权限为 0644。

ADD

用途:类似 COPY,但能处理 URL 和自动解压压缩文件。

示例:ADD https://example.com/archive.tar.gz /app/

说明:自动从指定的地址下载文件到 /app/下,并自动解压到/app下

WORKDIR

用途:设置工作目录,之后的 RUN, CMD, COPY, ADD 等指令将在这个目录下执行。而且这个镜像创建的容器启动后的工作目录也是这个。

示例:WORKDIR /app

说明:将 /app作为后续指令的工作目录,例如:

WORKDIR /app

ADD myfile .

RUN mkdir test

WORKDIR test

COPY a.html .

这一系列的指令意思是指定/app为默认工作目录,执行ADD从宿主机复制一个文件myfile到 镜像的/app下,然后用RUN在镜像的/app下创建

目录test,用WORKDIR指定默认工作目录为/app/test,使用COPY从宿主机复制文件a.html到镜像中的目录/app/test下

EXPOSE

用途:描述容器需要监听的端口,供服务映射。

示例:EXPOSE 8080

说明:这个指令只有文档性作用,描述了容器可能监听了哪些端口,端口是否真被监听,与这个指令无关。也就是说这个指令就算描述了一个没有被监听的端口,

对容器的运行也毫无影响。

ENV

用途:设置容器运行时环境变量。就是容器运行时容器中的系统变量

示例:ENV MY_VAR=value

说明:容器运行起来后,其中运行的应用就可以使用这个环境变量ENV MY_VAR,它在系统中是全局的。环境变量也可以不在Dockerfile中声明,而在容器创建时

声明并指定值。如果容器创建时声明的变量在 Dockerfile中也声明了,那么就用容器创建时声明的变量值覆盖Dockerfile中声明的变量值。

ARG

用途:设置构建镜像时变量,这个变量只在构建镜像时有用,镜像构建完毕就失效,不会出现在容器里

示例:ARG version=1.1.0或者ARG version

说明:ARG version=1.1.0定义了有默认值的变量,构建时不传入变量值就使用默认值或为空。docker build -t my_image --build-arg

VOLUME

用途:创建一个挂载点,用于持久化数据。

示例:VOLUME /data

说明:数据卷是docker中的一种数据存储结构,默认存储在宿主机的 /var/lib/docker/volumes 下。容器生成的数据可以存储在三个地方,数据卷,容器内部的文件系统,宿主机的文件系统。将数据卷挂载到容器目录上,那么这个目录中的内容就存储在数据卷上。将宿主机的目录挂载到容器的目录上,那么该容器目录中的内容就存储在宿主机上。否则数据就存储在容器的文件系统中,容器删除数据就丢失了。VOLUME /data这条指令会告诉docker,基于dockerfile创建的镜像在运行容器时,/data目录应被视为一个挂载点。这个指令并不会再构建镜像时创建数据卷和目录。在运行容器时如果没有将数据卷或宿主机目录挂载到/data目录,那么容器就会创建一个匿名卷挂载到/data上。VOLUME /data的目的是声明/data为持久化存储区域,在容器创建时会自动被挂载为卷,并且其中的数据独立与容器的生命周期。其它没有被声明为挂载点的目录在容器创建时依然可以挂载为卷,只是不能自动,需要用户手动挂载。

CMD

用途:指定容器启动时默认执行的命令,可以被 docker run 命令行参数覆盖。

示例:CMD ["python", "app.py"]

ENTRYPOINT

用途:配置容器启动时运行的命令,常与 CMD 配合使用。

示例:ENTRYPOINT ["java","-jar","test.jar"]

说明:如果即配置了ENTRYPOINT,也配置了CMD,那么CMD就作为ENTRYPOINT的参数.一般ENTRYPOINT配置的是不变的部分,容器启动时动态传入的参数使用CMD

配置。

docker常用的一些指令:

1、 查看 docker进程信息:

docker info

2、构建镜像:

docker build -t openjre:21 . -f openjre21

3、 查看镜像信息:

docker inspect <image_name>|<image_id>

4、查看镜像列表:

docker images

5、删除镜像,如果该镜像创建了运行的或没运行的容器,要先删除容器

docker rmi <image_name>|<image_id>

6、导出镜像为文件

docker save -o <filename> <image>,[<image>...]

7、从文件加载镜像

docker load -i <filename>

8、从镜像库拉取镜像

docker pull [OPTIONS] [REGISTRY_HOST[:PORT]/]NAME[:TAG|@DIGEST]

NAME:这是镜像的名称,通常包含仓库名称和镜像名称,例如 library/nginx。

TAG:这是镜像的标签,用于区分同一镜像的不同版本,例如 latest 或 1.15.0。如果不指定标签,默认为 latest。

DIGEST:这是镜像的SHA256摘要,用于精确指定要拉取的镜像版本。

在拉取私有库镜像前要先登录私有库. docker login host:port

9、向远程库推送镜像

docker push [OPTIONS] NAME[:TAG|@DIGEST]

NAME:这是镜像的全名,通常包含仓库名和镜像名,例如 username/myimage。

TAG:这是镜像的标签,用于区分同一镜像的不同版本,例如 latest 或 v1.0。

DIGEST:这是镜像的SHA256摘要,用于精确指定要推送的镜像版本。

10、为镜像打标签。这是一种为镜像命名的方法,使得镜像可以拥有多个名称或版本标识。

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

SOURCE_IMAGE:这是原始镜像的名称或ID,可以加上标签,例如 ubuntu:latest。

TARGET_IMAGE:这是新标签的名称,通常包括仓库名和镜像名,例如 myuser/myrepo:mytag

如果我有一个镜像名称是myimage,我想把它推送到我的私有库192.168.10.100:5000,可以这样操作

docker tag myimage 192.168.10.100:5000/myimage

docker push 192.168.10.100:5000/myimage

11、启动一个新容器,基于一个镜像。

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

IMAGE:要从其创建容器的镜像的名称或ID。

COMMAND:可选,要在容器中运行的命令。

ARG...:可选,传递给 COMMAND 的参数。

OPTIONS:运行容器的一些选项

-d, --detach:在后台运行容器,并返回容器ID。这对于运行长期运行的服务很有用。

-i, --interactive:保持STDIN打开,即使没有附加的客户端。

-t, --tty:分配一个伪TTY。通常与 -i 一起使用,为容器提供一个交互式终端。

-p, --publish:发布一个或多个端口到主机。格式为:hostPort:containerPort 或 hostIP:hostPort:containerPort。

-v, --volume:绑定一个卷到容器。指定的卷或宿主机目录不存在会自动创建。格式为:hostPath:containerPath 或 hostPath:containerPath:ro(只读)。

--mount :同-v,有时效果好于-v.格式为:source=myvolume,target=/app

--name:指定新容器的名称。

--env, -e:设置环境变量。例如:-e KEY=VALUE。这个KEY可以是Dockerfile中ENV定义的,也可以不是,如果是定义的就用VALUE覆盖

--network:指定容器加入的网络。

--restart:设置容器重启策略。

1、no:默认策略,在容器退出时不重启容器。

2、on-failure:在容器非正常退出时(退出状态非0),才会重启容器。此策略可以进一步指定重启次数,如 on-failure:3 表示在容器非正常退出时最多重启3次。

3、always:在容器退出时总是重启容器,无论退出状态是什么。

4、unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器。

--rm:在容器停止后自动删除容器。

--cap-add:添加Linux capabilities。

--device:添加一个主机设备到容器。

--entrypoint:覆盖镜像的 ENTRYPOINT。

--security-opt:设置安全选项。

--label:添加元数据到容器。

例如,以交互式方式启动一个容器

docker run -it --name myjdk --entrypoint="/bin/sh" 192.168.12.84:5000/openjdk-alpine:21

12、查看容器列表

docker ps -a

不加 -a 只显示运行中的容器,否则是全部的容器

13、启动容器

docker start <image-id>|<images-name>

14、停止容器

docker stop <image-id>|<images-name>

15、删除容器 ,必须先停止容器

docker rm <container-id>|<container-name>

16、显式创建数据卷

docker volume create myvolume

这会在Docker管理的卷存储位置中创建一个名为myvolume的数据卷,但此时它还没有被挂载到任何容器上。之后,你可以通过docker run命令中的--mount或-v/--volume标志将其挂载到容器上。

17、查看数据卷,列出Docker主机上所有的数据卷

docker volume ls

18、删除一个未在使用中的数据卷

docker volume rm myvolume

只有未挂载到任何容器上的数据卷才能被删除。如果尝试删除一个正在使用的数据卷,Docker会报错。

最近发表
标签列表