十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
前言
成都创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站制作、网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的徽州网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!Docker的口号是Build,Ship,and Run Any App,Anywhere,在我们使用 Docker 的大部分时候,的确能感觉到其优越性,但是往往在我们 Build 一个应用的时候,是将我们的源代码也构建进去的,这对于类似于 golang 这样的编译型语言肯定是不行的,因为实际运行的时候我只需要把最终构建的二进制包给你就行,把源码也一起打包在镜像中,需要承担很多风险,即使是脚本语言,在构建的时候也可能需要使用到一些上线的工具,这样无疑也增大了我们的镜像体积。
在应用了容器技术的软件开发过程中,控制容器镜像的大小可是一件费时费力的事情。如果我们构建的镜像既是编译软件的环境,又是软件最终的运行环境,这是很难控制镜像大小的。所以常见的配置模式为:分别为软件的编译环境和运行环境提供不同的容器镜像。比如为编译环境提供一个 Dockerfile.build,用它构建的镜像包含了编译软件需要的所有内容,比如代码、SDK、工具等等。同时为软件的运行环境提供另外一个单独的 Dockerfile,它从 Dockerfile.build 中获得编译好的软件,用它构建的镜像只包含运行软件所必须的内容。这种情况被称为构造者模式(builder pattern),本文将介绍如何通过 Dockerfile 中的 multi-stage 来解决构造者模式带来的问题。
常见的容器镜像构建过程
比如我们创建了一个 GO 语言编写了一个检查页面中超级链接的程序 app.go(请从 sparkdev (本地下载)获取本文相关的代码):
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)) }