GVKun编程网logo

Docker镜像瘦身:从1.43G到22.4MB(docker 镜像瘦身)

5

以上就是给各位分享Docker镜像瘦身:从1.43G到22.4MB,其中也会对docker镜像瘦身进行解释,同时本文还将给你拓展13.Manifest实现多CPU架构Docker镜像(Docker镜像

以上就是给各位分享Docker镜像瘦身:从1.43G到22.4MB,其中也会对docker 镜像瘦身进行解释,同时本文还将给你拓展13.Manifest实现多CPU架构Docker镜像(Docker 镜像跨平台使用)、Docker & ASP.NET Core (2):定制Docker镜像、Docker for Windows(三)Docker镜像与容器的区别&常用命令、docker history 查看docker镜像构建过程 还原dockerfile 查看启动参数等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

Docker镜像瘦身:从1.43G到22.4MB(docker 镜像瘦身)

Docker镜像瘦身:从1.43G到22.4MB(docker 镜像瘦身)

Docker 镜像的大小对于系统的 CI/CD 等都有影响,尤其是云部署场景。我们在生产实践中都会做瘦身的操作,尽最大的可能使用 Size 小的镜像完成功能。

下文是一个简单的 ReactJS 程序上线的瘦身体验,希望可以帮助大家找到镜像瘦身的方向和灵感。

如果你正在做 Web 开发相关工作,那么你可能已经知道容器化的概念,以及知道它强大的功能等等。

但在使用 Docker 时,镜像大小至关重要。我们从 create-react-app (https://reactjs.org/docs/create-a-new-react-app.html)获得的样板项目通常都超过 1.43 GB。

今天,我们将容器化一个 ReactJS 应用程序,并学习一些关于如何减少镜像大小并提高性能的技巧。

我们将以 ReactJS 为例,但它适用于任何类型的 NodeJS 应用程序。

步骤 1:创建项目
①借助脚手架通过命令行模式创建 React 项目:

npx create-react-app docker-image-test
②命令执行成功后将生成一个基础 React 应用程序架构。

③我们可以进入项目目录安装依赖并运行项目:

cd docker-image-test
yarn install
yarn start

④通过访问 http://localhost:3000 可以访问已经启动的应用程序。

步骤 2:构建第一个镜像
①在项目的根目录中创建一个名为 Dockerfile 的文件,并粘贴以下代码:

FROM node:12

WORKDIR /app

COPY package.json ./

RUN yarn install

COPY . .

EXPOSE 3000

CMD ["yarn", "start"]

②注意,这里我们从 Docker 仓库获得基础镜像 Node:12,然后安装依赖项并运行基本命令。

③现在可以通过终端为容器构建镜像:

docker build -t docker-image-test .
④Docker 构建镜像完成之后,你可以使用此命令查看已经构建的镜像:

docker images
在查询结果列表的顶部,是我们新创建的图像,在最右边,我们可以看到图像的大小。目前是 1.43GB。

⑤我们使用以下命令运行镜像:

docker run --rm -it -p 3000:3000/tcp docker-image-test:latest

打开浏览器并且刷新页面验证其可以正常运行。

步骤 3:修改基础镜像
①先前的配置中我们用 node:12 作为基础镜像。但是传统的 Node 镜像是基于 Ubuntu 的,对于我们简单的 React 应用程序来说这大可不必。

②从 DockerHub(官方 Docker 镜像注册表)中我们可以看到,基于 alpine-based 的 Node 镜像比基于 Ubuntu 的镜像小得多,而且它们的依赖程度非常低。

③下面显示了这些基本图像的大小比较:

现在我们将使用node:12-alpine作为我们的基础镜像,看看会发生什么。

FROM node:12-alpine

WORKDIR /app

COPY package.json ./

RUN yarn install

COPY . .

EXPOSE 3000

CMD ["yarn", "start"]

然后我们以此构建我们的镜像,并与之前做对比。

哇!我们的镜像大小减少到只有 580MB,这是一个很大的进步。但还能做得更好吗?

步骤 4:多级构建
①在之前的配置中,我们会将所有源代码也复制到工作目录中。

②但这大可不必,因为从发布和运行来看我们只需要构建好的运行目录即可。因此,现在我们将引入多级构建的概念,以减少不必要的代码和依赖于我们的最终镜像。

③配置是这样的:

# STAGE 1

FROM node:12-alpine AS build

WORKDIR /app

COPY package.json ./

RUN yarn  install

COPY . /app

RUN yarn build


# STAGE 2

FROM node:12-alpine

WORKDIR /app

RUN npm install -g webserver.local

COPY --from=build /app/build ./build

EXPOSE 3000

CMD webserver.local -d ./build

④在第一阶段,安装依赖项并构建我们的项目。

⑤在第二阶段,我们复制上一阶段构建产物目录,并使用它来运行应用程序。

⑥这样我们在最终的镜像中就不会有不必要的依赖和代码。

接下来,构建镜像成功后并从列表中查看镜像:

现在我们的镜像大小只有 97.5MB。这简直太棒了。

步骤 5:使用 Nginx
①我们正在使用 Node 服务器运行 ReactJS 应用程序的静态资源,但这不是静态资源运行的最佳选择。

②我们尝试使用 Nginx 这类更高效、更轻量级的服务器来运行资源应用程序,也可以尽可能提高其性能,并且减少镜像的量。

③我们最终的 Docker 配置文件看起来像这样:

# STAGE 1

FROM node:12-alpine AS build

WORKDIR /app

COPY package.json ./

RUN yarn  install

COPY . /app

RUN yarn build

# STAGE 2

FROM nginx:stable-alpine

COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

④我们正在改变 Docker 配置的第二阶段,以使用 Nginx 来服务我们的应用程序。

⑤然后使用当前配置构建镜像。

⑥镜像大小减少到只有 22.4MB!

⑦同时,我们正在使用一个性能更好的服务器来服务我们出色的应用程序。

⑧我们可以使用以下命令验证应用程序是否仍在工作。

docker run --rm  -it -p 3000:80/tcp docker-image-test:latest

⑨注意,我们将容器的 80 端口暴露给外部,因为默认情况下,Nginx 将在容器内部的 80 端口上可用。

所以这些是一些简单的技巧,你可以应用到你的任何 NodeJS 项目,以大幅减少镜像大小。

现在,您的容器确实更加便携和高效了。今天就到这里。编码快乐!

13.Manifest实现多CPU架构Docker镜像(Docker 镜像跨平台使用)

13.Manifest实现多CPU架构Docker镜像(Docker 镜像跨平台使用)

原文:https://www.jianshu.com/p/fad6b6fb4599

1、manifest是什么,干什么用?

manifest是一个文件,这个文件包含了有关于镜像信息,如层、大小和摘要。docker manifest命令还向用户提供附加信息,比如构建镜像的操作系统和体系结构。而manifest list是一个镜像清单列表,用于存放多个不同os/arch的镜像信息。我们可以创建一个manifest list来指向两个镜像(一个linux 64位和一个指向arm64位的镜像),然后对用户提供一个唯一的镜像名称。从Docker registry v2.3和Docker 1.10 开始,Docker hub就可以pull multi architecture Docker镜像了。

一个镜像的manifest文件信息如下:

[root@localhost ~]# docker manifest inspect java
{
        "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 4733, "digest": "sha256:d23bdf5b1b1b1afce5f1d0fd33e7ed8afbc084b594b9ccf742a5b27080d8a4a8" }, "layers": [ #---镜像层的摘要信息 { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 51361210, "digest": "sha256:5040bd2983909aa8896b9932438c3f1479d25ae837a5f6220242a264d0221f2d" }, ................... ] } 

一个manifest list的例子如下:

{
   "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 1357, "digest": "sha256:9b47044b1e79b965a8e1653e7f9c04b5f63e00b9161bedd5baef69bb8b4c4834", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 1357, "digest": "sha256:8aecae775e1f81d3889929ef15647187b414c833b0798d060bfd778bee668ced", "platform": { "architecture": "arm64", "os": "linux", "variant": "v8" } } ] } 

注意:manifest的功能目前仅仅作用于docker 官方的镜像仓库。

总结:简单的说manifest list就是多个manifest的一个集合,通过列表方式来管理。


2、manifest list处理流程:

 
manifest-2.jpg
 
docker-manifest.png

3、开启docker子命令manifest功能:

manifest是做为docker客户端的子命令存在,不过这个子命令目前处在实验性中一般没有开启。我们需要手动开始这个子命令的功能。开启过程如下:

1)、编辑配置文件config.json应用实验性功能:
docker 的默认配置文件config.json是在$HOME目录下的.docker目录下。编辑config.json文件,若目录和文件不存在手动创建。

$vim ~/.docker/config.json { "experimental": "enabled" } 

2)、编辑守护进程配置文件daemon.json开启实验性功能:
编辑daemon.json,若目录和文件不存在手动创建

$vim /etc/docker/daemon.json
{
  "experimental": true
}

3)、重启docker:

$systemctl daemon-reload
$service docker restart
$docker manifest --help #----查看manifest帮助信息

开启docker的实验性功能后docker pull可以拉取指定平台镜像如下:

$docker pull --platform arm64  镜像
--platform:该参数是用于拉取指定平台的镜像,也是实验性功能,在上面步骤中开启后就会出现。通
过该参数可以手动指定需要的CPU平台镜像,而不用自动去识别。

4、使用manifest创建多CPU架构的镜像:

查看一个镜像的manifest文件信息
$docker manifest inspect java

查看一个镜像的manifest文件的详细信息包括cpu平台架构等信息
$docker manifest inspect --verbose java

这里准备好了两个不同CPU架构的镜像如下:
这里的镜像是自己在docker hub上创建的仓库
xxx/public_docker:nginx-arm64
xxx/public_docker:nginx-x86
将上面两个镜像推到docker hub上面

1)、创建一个manifest list列表:
创建一个自定义命名的镜像名的manifest list,然后用该列表关联仓库里面的两个不同架构的镜像
$docker manifest create xxx/public_docker:nginx-v1 xxx/public_docker:nginx-arm64 xxx/public_docker:nginx-x86

2)、将创建好的manifest list 推到仓库中:
$docker manifest push xxx/public_docker:nginx-v1

3)、查看仓库中创建好的manifest list:
$docker manifest inspect xxx/public_docker:nginx-v1


补充:

在我们拉取镜像时显示的摘要(Digest):

就是对镜像的 manifest 内容计算 sha256sum 得到的。

 

Docker & ASP.NET Core (2):定制Docker镜像

Docker & ASP.NET Core (2):定制Docker镜像

上一篇文章:把代码连接到容器 

Dockerfile

在Docker的世界里,我们可以通过一个叫Dockerfile的文件来创建Docker镜像,随后可以运行容器。

Dockerfile就是一个文本文件,里面写着一些指令。通过Docker Client,并使用docker build这个命令,docker build命令会读取该文件里面的指令,生成一层文件系统,然后就生产出了一个docker的镜像。

Dockerfile的文件名就是Dockerfile,当然了也可以叫别的名,但是通常就叫Dockerfile。

Dockerfile里面包含着各种指令,这些指令会创建一个中间层镜像,这个中间层镜像可以被缓存,这样的话以后构建的时候速度就很快了。

 

Dockerfile的主要指令:

  • FROM。通常情况下,你要创建的镜像是基于另外一个镜像的,这就需要使用FROM,当然也可以完全从头创建。
  • MAINTAINER。该镜像的维护人。
  • RUN。这里可以定义一些需要运行的命令。例如npm install,dotnet restore等等。
  • COPY。开发的时候,可以把源码放在Volumes里。而在生产环境下,经常需要把源码复制到容器里面,使用COPY就可以做到这点。
  • ENTRYPOINT。它可以定义容器的入口,把容器配置成像exe一样的运行文件。通常是一些例如dotnet 命令,node命令等等。
  • CMD。设置容器运行的默认命令和参数。当容器运行的时候,这个可以在命令行被覆盖。
  • WORKDIR。设定容器运行的工作目录。
  • EXPOSE。暴露端口。
  • ENV。设定环境变量。
  • VOLUME。定义Volume,并控制如何在宿主中进行存储。

 

下面是官网的一个Dockerfile的例子:

 

FROM python:27.-slim,说明该镜像要基于python:2.7-slim这个镜像构建。这将会是一层。

COPY . /app,是指在构建镜像的时候,从当前目录把源码复制到/app目录下。这又是一层。

RUN xxx,是指在WORKDIR(/app)下执行pip install xxx这行命令。

EXPOSE 80,是指把容器的80端口暴露给外界。

ENV,定义了环境变量。

CMD ["python", "app.py"],里定义了容器运行的默认命令和参数。

 

创建一个ASP.NET Core Dockerfile

在Docker hub里找到aspnetcore:

里面第一个microsoft/aspnetcore 只有运行时,所以只能dotnet run,适用于生产环境。

第二个microsoft/aspnetcore-build里有完整的dotnet sdk,可以执行dotnet restore, dotnet build, dotnet run等等。

 

使用VSCode打开我上篇文章建立的ASP.NET Core项目(或者新建一个也可以):

 

然后我们这样来创建Dockerfile,首先点击Extensions,搜索docker:

可以找到一个Docker扩展,是由微软开发的。安装它即可。

 

安装完后,点击Docker按个图标:

就可以看到本机上的Docker镜像,容器,注册信息等等。

 

然后按Ctrl+Shift+P,然后输入docker:

可以看到有很多可用的命令。

选择Add Docker Files to Workspace,然后选择ASP.NET Core:

 

然后选择操作系统,这里我选Linux:

 

然后填写内部的端口,我这个项目是5001:

 

然后按回车,就会生成Dockerfile,同时还有一个.dockerignore文件:

(在编辑Dockerfile文件的时候还有智能提示的)。

看一下这个文件:

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base,就是把前面的镜像起了一个别名,叫做base。

WORKDIR /app,工作目录是 /app。

端口5001。

下面几句类似,然后:

COPY ["VolumeSample.csproj", "./"],就是把VolumeSample.csproj复制到当前工作的目录。

RUN dotnet restore "./VolumeSample.csproj",执行dotnet restore。

COPY . .,然后把所有的源码也复制到当前的工作目录。

WORKDIR "/src/.",切换工作目录到/src。

RUN dotnet build "VolumeSample.csproj" -c Release -o /app,再执行dotnet build命令,并把结果放在/app目录下。

 

后边几句也是类似:

COPY --from=publish /app .,是指从publish目录复制,具体是从publish/app目录复制,到当前的工作目录。

ENTRYPOINT ["dotnet", "VolumeSample.dll"],就是运行该镜像会执行的命令dotnet VolumeSample.dll。
 
(一个项目里可以有多个Dockerfile,例如区分开发和生产环境,但是文件名最好使用dockerfile后缀,因为这样在VSCode里有智能提示)。
 

创建镜像

其实上面使用VSCode生成的Dockerfile并不是我需要的,我需要的Dockerfile还是按照官方文档来吧:

https://github.com/aspnet/aspnet-docker/blob/master/README.aspnetcore-build.md

最后是这样的:

也是多个Stage的。

 

然后执行这个命令来构建镜像:

docker build -t solenovex/aspnetcore .

使用docker build,-t表示tag,然后是用户名和要起的镜像名,镜像名后边可以跟着具体的tag,例如solenovex/aspnetcore:1.0,如果不加的话就是latest。最后一个.表示当前这个含有Dockerfile目录是我要进行构建的内容。

 

执行的时候会遇到.net sdk版本不匹配的问题,也就是microsoft/aspnetcore-build这个镜像的.net sdk版本有点低。

 

所以,我只好改为使用microsoft/dotnet:2.1-sdk这个镜像了:

 

再次执行:docker build -t solenovex/aspnetcore .

这个构建的过程还是挺快的,过程大概如下:

成功了。

 

然后从VSCode的docker扩展里就可以看到我刚刚创建的镜像:

 

然后在Powershell里面创建/运行一个容器:

 

执行docker ps -a:

可以看到该容器运行后就马上退出了,查看一下日志看看原因:

 

错误信息是:

其实这个错误信息感觉并不明确。

 

具体怎么解决这个错误,且听下回分解。。

Docker for Windows(三)Docker镜像与容器的区别&常用命令

Docker for Windows(三)Docker镜像与容器的区别&常用命令

Docker镜像(Image)是一堆只读文件(read-only layer),容器(container)的定义和镜像(image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
容器 = 镜像 + 读写层。

Docker常用命令:

docker version显示 Docker 版本信息
docker info显示 Docker 系统信息,包括镜像和容器数
docker pull <image-id>拉取或者更新指定镜像
docker create <image-id>创建镜像
docker create 命令为指定的镜像(image)添加了一个可读写层,构成了一个新的容器。注意,这个容器并没有运行。


docker start <container-id>启动容器
docker start命令为容器文件系统创建了一个进程隔离空间。注意,每一个容器只能够有一个进程隔离空间。


docker run <image-id>启动镜像
看到这个命令,读者通常会有一个疑问:docker start 和 docker run命令有什么区别。


实际上,docker run 命令先是利用镜像创建了一个容器,然后运行这个容器。这个命令非常的方便,并且隐藏了两个命令的细节,但从另一方面来看,这容易让用户产生误解。


docker ps 查看所有运行中的容器。
这隐藏了非运行态容器的存在,如果想要找出这些容器,我们需要使用docker ps –a这个命令。


docker images 命令会列出所有顶层镜像。
实际上,在这里我们没有办法区分一个镜像和一个只读层,所以我们提出了top-level镜像。只有创建容器时使用的镜像或者是直接pull下来的镜像能被称为顶层(top-level)镜像,并且每一个顶层镜像下面都隐藏了多个镜像层。


docker images –a命令列出了所有的镜像,也可以说是列出了所有的可读层。如果你想要查看某一个image-id下的所有层,可以使用docker history来查看。


docker stop <container-id>停止所有的进程docker stop命令会向运行中的容器发送一个SIGTERM的信号,然后停止所有的进程。


docker kill <container-id>杀死进程,docker kill 命令向所有运行在容器中的进程发送了一个不友好的SIGKILL信号。


docker rm <container-id>命令会移除构成容器的可读写层。注意,这个命令只能对非运行态容器执行。


docker rmi <image-id>命令会移除构成镜像的一个只读层。你只能够使用docker rmi来移除最顶层(top level layer)(也可以说是镜像),你也可以使用-f参数来强制删除中间的只读层。


docker commit <container-id>命令将容器的可读写层转换为一个只读层,这样就把一个容器转换成了不可变的镜像。


docker build我们从上图可以看到,build命令根据Dockerfile文件中的FROM指令获取到镜像,然后重复地1)run(create和start)、2)修改、3)commit。在循环中的每一步都会生成一个新的层,因此许多新的层会被创建。


docker exec <running-container-id>docker exec 命令会在运行中的容器执行一个新进程。


docker inspect <container-id>查看这个容器的详细信息,例如查看运行的数据库服务的连接信息。


docker save <image-id>docker save命令会创建一个镜像的压缩文件,这个文件能够在另外一个主机的Docker上使用。和export命令不同,这个命令为每一个层都保存了它们的元数据。这个命令只能对镜像生效。


docker export <container-id>docker export命令创建一个tar文件,并且移除了元数据和不必要的层,将多个层整合成了一个层,只保存了当前统一视角看到的内容(译者注:expoxt后的容器再import到Docker中,通过docker images –tree命令只能看到一个镜像;而save后的镜像则不同,它能够看到这个镜像的历史镜像)。


docker history <image-id>docker history命令递归地输出指定镜像的历史镜像。


firewall-cmd --add-port=3306/tcp开放端口
systemctl stop firewalld关闭防火墙

 

docker history 查看docker镜像构建过程 还原dockerfile 查看启动参数

docker history 查看docker镜像构建过程 还原dockerfile 查看启动参数

介绍:

~]# docker history --help
Usage:  docker history [OPTIONS] IMAGE
Show the history of an image
Options:
      --format string   Pretty-print images using a Go template
      --help            Print usage
  -H,--human           Print sizes and dates in human readable format (default true)
      --no-trunc        Don't truncate output
  -q,--quiet           Only show numeric IDs

示例:

~]# docker history kubeguide/tomcat-app:v1
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a29e200a18e9        2 years ago         /bin/sh -c #(nop) ADD dir:c5c3bddef49cbc9f...   992kB               
<missing>           2 years ago         /bin/sh -c #(nop) MAINTAINER bestme <bestm...   0B                  
<missing>           2 years ago         /bin/sh -c #(nop) CMD ["catalina.sh" "run"]     0B                  
<missing>           2 years ago         /bin/sh -c #(nop) EXPOSE 8080/tcp               0B                  
<missing>           2 years ago         /bin/sh -c set -e  && nativeLines="$(catal...   0B                  
<missing>           2 years ago         /bin/sh -c set -x   && curl -fSL "$TOMCAT_...   16.6MB              
<missing>           2 years ago         /bin/sh -c #(nop) ENV TOMCAT_TGZ_URL=https...   0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV TOMCAT_VERSION=8.0.35     0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV TOMCAT_MAJOR=8            0B                  
<missing>           2 years ago         /bin/sh -c set -ex  && for key in   05AB33...   114kB               
<missing>           2 years ago         /bin/sh -c apt-get update && apt-get insta...   7.18MB              
<missing>           2 years ago         /bin/sh -c {   echo 'deb http://httpredir....   172B                
<missing>           2 years ago         /bin/sh -c #(nop) ENV OPENSSL_VERSION=1.0....   0B                  
<missing>           2 years ago         /bin/sh -c #(nop) workdir /usr/local/tomcat     0B                  
<missing>           2 years ago         /bin/sh -c mkdir -p "$CATALINA_HOME"            0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV PATH=/usr/local/tomc...   0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV CATALINA_HOME=/usr/l...   0B                  
<missing>           2 years ago         /bin/sh -c set -x  && apt-get update  && a...   163MB               
<missing>           2 years ago         /bin/sh -c #(nop) ENV JAVA_DEBIAN_VERSION=...   0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV JAVA_VERSION=7u101        0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ENV JAVA_HOME=/usr/lib/j...   0B                  
<missing>           2 years ago         /bin/sh -c {   echo '#!/bin/sh';   echo 's...   87B                 
<missing>           2 years ago         /bin/sh -c #(nop) ENV LANG=C.UTF-8              0B                  
<missing>           2 years ago         /bin/sh -c apt-get update && apt-get insta...   1.17MB              
<missing>           2 years ago         /bin/sh -c apt-get update && apt-get insta...   44.3MB              
<missing>           2 years ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0B                  
<missing>           2 years ago         /bin/sh -c #(nop) ADD file:5d8521419ad6cfb...   125MB

如果要让CREATED BY 列完整显示,可以加上 --no-trunc 参数。直接在shell中看会比较乱,可以输出到文件查看,就比较直观了

以PHPmyadmin docker镜像为例,效果如下:

 

 

 

 

我们今天的关于Docker镜像瘦身:从1.43G到22.4MBdocker 镜像瘦身的分享已经告一段落,感谢您的关注,如果您想了解更多关于13.Manifest实现多CPU架构Docker镜像(Docker 镜像跨平台使用)、Docker & ASP.NET Core (2):定制Docker镜像、Docker for Windows(三)Docker镜像与容器的区别&常用命令、docker history 查看docker镜像构建过程 还原dockerfile 查看启动参数的相关信息,请在本站查询。

本文标签: