Dockerfile中multi-stage怎么构建

发布时间:2022-05-20 15:20:28 作者:iii
来源:亿速云 阅读:159

本篇内容介绍了“Dockerfile中multi-stage怎么构建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

常见的容器镜像构建过程

比如我们创建了一个 go 语言编写了一个检查页面中超级链接的程序 app.go(请从  ()获取本文相关的代码):

package main
import (
 "encoding/json"
 "fmt"
 "log"
 "net/http"
 "net/url"
 "os"
 "strings"
 "golang.org/x/net/html"
)
type scrapedatastore struct {
 internal int `json:"internal"`
 external int `json:"external"`
}
func isinternal(parsedlink *url.url, siteurl *url.url, link string) bool {
 return parsedlink.host == siteurl.host || strings.index(link, "#") == 0 || len(parsedlink.host) == 0
}
func main() {
 urlin := os.getenv("url")
 if len(urlin) == 0 {
 urlin = "https://www.cnblogs.com/"
 }
 resp, err := http.get(urlin)
 scrapedata := &scrapedatastore{}
 tokenizer := html.newtokenizer(resp.body)
 end := false
 for {
 tt := tokenizer.next()
 switch {
 case tt == html.starttagtoken:
 token := tokenizer.token()
 switch token.data {
 case "a":
 for _, attr := range token.attr {
  if attr.key == "href" {
  link := attr.val
  parsedlink, parselinkerr := url.parse(link)
  if parselinkerr == nil {
  if isinternal(parsedlink, siteurl, link) {
  scrapedata.internal++
  } else {
  scrapedata.external++
  }
  }
  if parselinkerr != nil {
  fmt.println("can't parse: " + token.data)
  }
  }
 }
 break
 }
 case tt == html.errortoken:
 end = true
 break
 }
 if end {
 break
 }
 }
 data, _ := json.marshal(&scrapedata)
 fmt.println(string(data))
}

下面我们通过容器来构建它,并把它部署到生产型的容器镜像中。

首先构建编译应用程序的镜像:

from golang:1.7.3
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .

把上面的内容保存到 dockerfile.build 文件中。

接着把构建好的应用程序部署到生产环境用的镜像中:

from alpine:latest 
run apk --no-cache add ca-certificates
workdir /root/
copy app .
cmd ["./app"]

把上面的内容保存到 dockerfile 文件中。

最后需要使用一个脚本把整个构建过程整合起来:

#!/bin/sh
echo building sparkdevo/href-counter:build
# 构建编译应用程序的镜像
docker build --no-cache -t sparkdevo/href-counter:build . -f dockerfile.build
# 创建应用程序
docker create --name extract sparkdevo/href-counter:build
# 拷贝编译好的应用程序
docker cp extract:/go/src/github.com/sparkdevo/href-counter/app ./app
docker rm -f extract

echo building sparkdevo/href-counter:latest
# 构建运行应用程序的镜像
docker build --no-cache -t sparkdevo/href-counter:latest .

把上面的内容保存到 build.sh 文件中。这个脚本会先创建出一个容器来构建应用程序,然后再创建最终运行应用程序的镜像。

把 app.go、dockerfile.build、dockerfile 和 build.sh 放在同一个目录下,然后进入这个目录执行 build.sh 脚本进行构建。构建后的容器镜像大小:

Dockerfile中multi-stage怎么构建

从上图中我们可以观察到,用于编译应用程序的容器镜像大小接近 700m,而用于生产环境的容器镜像只有 10.3 m,这样的大小在网络间传输的效率是很高的。

运行下面的命令可以检查我们构建的容器是否可以正常的工作:

$ docker run -e url=https://www.cnblogs.com/ sparkdevo/href-counter:latest
$ docker run -e url=http://www.cnblogs.com/sparkdev/ sparkdevo/href-counter:latest

Dockerfile中multi-stage怎么构建

ok,我们写的程序正确的统计了博客园首页和笔者的首页中超级链接的情况。

采用上面的构建过程,我们需要维护两个 dockerfile 文件和一个脚本文件 build.sh。能不能简化一些呢? 下面我们看看 docker 针对这种情况提供的解决方案:multi-stage。

在 dockerfile 中使用 multi-stage

multi-stage 允许我们在 dockerfile 中完成类似前面 build.sh 脚本中的功能,每个 stage 可以理解为构建一个容器镜像,后面的 stage 可以引用前面 stage 中创建的镜像。所以我们可以使用下面单个的 dockerfile 文件实现前面的需求:

from golang:1.7.3
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .

from alpine:latest
run apk --no-cache add ca-certificates
workdir /root/
copy --from=0 /go/src/github.com/sparkdevo/href-counter/app .
cmd ["./app"]

把上面的内容保存到文件 dockerfile.multi 中。这个 dockerfile 文件的特点是同时存在多个 from 指令,每个 from 指令代表一个 stage 的开始部分。我们可以把一个 stage 的产物拷贝到另一个 stage 中。本例中的第一个 stage 完成了应用程序的构建,内容和前面的 dockerfile.build 是一样的。第二个 stage 中的 copy 指令通过 --from=0 引用了第一个 stage ,并把应用程序拷贝到了当前 stage 中。接下来让我们编译新的镜像:

$ docker build --no-cache -t sparkdevo/href-counter:multi . -f dockerfile.multi

这次使用 href-counter:multi 镜像运行应用:

$ docker run -e url=https://www.cnblogs.com/ sparkdevo/href-counter:multi
$ docker run -e url=http://www.cnblogs.com/sparkdev/ sparkdevo/href-counter:multi

Dockerfile中multi-stage怎么构建

结果和之前是一样的。那么新生成的镜像有没有特别之处呢:

Dockerfile中multi-stage怎么构建

好吧,从上图我们可以看到,除了 sparkdevo/href-counter:multi 镜像,还生成了一个匿名的镜像。因此,所谓的 multi-stage 不过时多个 dockerfile 的语法糖罢了。但是这个语法糖还好很诱人的,现在我们维护一个结构简洁的 dockerfile 文件就可以了!

使用命名的 stage

在上面的例子中我们通过 --from=0 引用了 dockerfile 中第一个 stage,这样的做法会让 dockerfile 变得不容易阅读。其实我们是可以为 stage 命名的,然后就可以通过名称来引用 stage 了。下面是改造后的 dockerfile.mult 文件:

from golang:1.7.3 as builder
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .

from alpine:latest
run apk --no-cache add ca-certificates
workdir /root/
copy --from=builder /go/src/github.com/sparkdevo/href-counter/app .
cmd ["./app"]

我们把第一个 stage 使用 as 语法命名为 builder,然后在后面的 stage 中通过名称 builder 进行引用 --from=builder。通过使用命名的 stage, dockerfile 更容易阅读了。

“Dockerfile中multi-stage怎么构建”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. 根据Dockerfile构建镜像
  2. 怎么在docker中利用Dockerfile构建镜像

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

dockerfile multi-stage

上一篇:在docker中如何运行mariadb程序

下一篇:Dockerfile中的CMD和ENTRYPOINT命令怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》