您当前的位置:首页 > 电脑百科 > 程序开发 > 容器

不用Docker也能构建容器的4种方法

时间:2020-12-15 11:17:34  来源:  作者:

在本文,我将介绍几种不用 Docker 就可以构建容器的方法。我将以 OpenFaaS 作为参考案例,它的工作负载使用了 OCI 格式的容器镜像。OpenFaaS 是 Kubernetes 的一个 CaaS 平台,可以运行微服务和添加 FaaS 及事件驱动工具。

第一个示例将展示如何使用 Docker CLI 内置的 buildkit 选项,然后是单独使用buildkit,最后是谷歌的容器构建器Kaniko。

本文涉及的工具都是基于 Dockerfile 文件来构建镜像的,因此,任何限制用户只能使用 JAVA (jib)或 Go (ko)的工具都不在讨论范围之内。

Docker 有什么问题?

Docker 在 armhf、arm64 和x86_64平台上运行良好。Docker CLI 不仅用于构建/发布/运行镜像,多年来它还背负了太多的东西,现在还与 Docker Swarm 和 Docker EE 特性捆绑在一起。

Docker 之外的选择

有一些项目试图让“docker”回到它原本的组件身份,也就是我们最初都喜爱的用户体验:

  • Docker——Docker现在使用containerd来运行容器,并且支持使用buildkit进行高效的缓存式构建。
  • Podman和buildah组合——由RedHat/IBM使用他们自己的OSS工具链来生成OCI镜像。Podman是无守护进程和无根的,但最后仍然需要挂载文件系统以及使用UNIX套接字。
  • pouch——来自阿里巴巴,被标榜为“高效的企业级容器引擎”。它像Docker一样,使用了containerd,并支持容器级别的隔离(runc)和“轻量级虚拟机”(如runV)。
  • 独立版本的buildkit——buildkit是由Docker公司的Tonis Tiigi创建的,一个全新的具有缓存和并发支持的容器构建器。buildkit目前仅作为守护进程运行,但你可能会听到有人说不是这样的。实际上,它会派生守护进程,然后在构建后将其终止。
  • img——img由Jess Frazelle开发,对buildkit进行了封装。与其他工具相比,它并没有更大的吸引力。在2018年下半年之前,这个项目一直很活跃,但之后只发布了几个补丁。img声称自己是无守护进程的,但它使用的是buildkit,所以这里有值得商榷的地方。我听说img提供了比buildkit的CLI buildctr更好的用户体验,但需要注意的是,img只针对x86_64平台发布了二进制文件,不支持armhf/arm64。
  • k3c——使用containerd和buildkit重建初始Docker原始、经典、朴素、轻量级的体验。

在所有的选项中,我最喜欢 k3c,但它使用起来比较繁琐,它把所有东西都捆绑在一个二进制文件中,这很可能会与其他软件发生冲突。它运行的是自己的嵌入式 containerd 和 buildkit 二进制文件。

由于我们关注的是“构建”部分以及相对稳定的选项,所以我们将着重看一下:

  • Docker的buildkit;
  • 单独的buildkit;
  • kaniko。

由于 OpenFaaS CLI 可以输出任意构建器都可以使用的标准“构建上下文”,所以上述的所有东西都可以实现。

构建一个测试应用程序

让我们从一个 Golang HTTP 中间件开始,并借此来展示 OpenFaaS 的通用性。

  • --lang指定构建模板;
  • build-test是函数的名字;
  • --prefix是Docker Hub用户名,用于推送我们的OCI镜像。

我们将获得以下这些内容:

./
├── build-test
│   └── handler.go
└── build-test.yml


1 directory, 2 files

处理程序修改起来很容易,还可以通过 vendoring 或 Go 模块来添加其他依赖项。

package function


import (
	"fmt"
	"io/ioutil"
	"net/http"
)


func Handle(w http.ResponseWriter, r *http.Request) {
	var input []byte


	if r.Body != nil {
		defer r.Body.Close()


		body, _ := ioutil.ReadAll(r.Body)


		input = body
	}


	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf("Hello world, input was: %s", string(input))))
}

使用一般的方式构建

构建这个应用程序的一般方式是这样的:

faas-cli build -f build-test.yml

./template/golang-middleware/Dockerfile中包含了模板和 Dockerfile 的本地缓存。

这次构建拉取了三个镜像:

FROM openfaas/of-watchdog:0.7.3 as watchdog
FROM golang:1.13-alpine3.11 as build
FROM alpine:3.12

如果使用传统的构建器,将按顺序拉取每个镜像。

等一会儿构建就完成了,现在本地库中就有了构建的镜像。

我们还可以使用 faas-cli push -f build-test.yml将镜像推到注册表中。

不用Docker也能构建容器的4种方法

 

使用 buildkit 和 Docker 构建

这是最简单的做法,构建起来也很快。

DOCKER_BUILDKIT=1 faas-cli build -f build-test.yml

我们可以看到,Docker 守护进程会自动切换到 buildkit 构建器。

Buildkit 有很多优点:

  • 更复杂的缓存;
  • 如果可能的话,可以先运行后面的指令——也就是说,可以在“sdk”层的构建完成之前,下载“runtime”镜像;
  • 在第二次构建时速度超级快。

有了 buildkit,所有的基础镜像都可以一次性被拉取到本地库中,因为 FROM(下载)命令不是按顺序执行的。

FROM openfaas/of-watchdog:0.7.3 as watchdog
FROM golang:1.13-alpine3.11 as build
FROM alpine:3.11

这个在 mac 上也可以使用,因为 buildkit 是由运行在 VM 中 Docker 守护进程负责代理的。

不用Docker也能构建容器的4种方法

 

使用单独的 buildkit 构建

要单独使用 buildkit 进行镜像构建,我们需要在 linux 主机上单独运行 buildkit,因此不能使用 Mac。

faas-cli build通常会运行或分叉出 docker,因为这个命令实际上只是一个包装器。因此,为了绕过这种行为,我们需要创建一个构建上下文,类似下面这样:

faas-cli build -f build-test.yml --shrinkwrap


[0] > Building build-test.
Clearing temporary build folder: ./build/build-test/
Preparing ./build-test/ ./build/build-test//function
Building: alexellis2/build-test:latest with golang-middleware template. Please wait..
build-test shrink-wrApped to ./build/build-test/
[0] < Building build-test done in 0.00s.
[0] Worker done.


Total build time: 0.00

这个上下文可以在./build/build-test/文件夹中找到,其中包含了函数代码和模板及其入口点和 Dockerfile。

./build/build-test/
├── Dockerfile
├── function
│   └── handler.go
├── go.mod
├── main.go
└── template.yml


1 directory, 5 files

现在我们需要运行 buildkit,可以从源代码开始构建,或者从上游获取二进制文件。

curl -sSLf https://github.com/moby/buildkit/releases/download/v0.6.3/buildkit-v0.6.3.linux-amd64.tar.gz | sudo tar -xz -C /usr/local/bin/ --strip-components=1

如果你仔细看一下发布页,你会发现 buildkit 也支持 armhf 和 arm64。

在新窗口中运行 buildkit 守护进程:

sudo buildkitd 
WARN[0000] using host network as the default            
INFO[0000] found worker "l1ltft74h0ek1718gitwghjxy", labels=map[org.mobyproject.buildkit.worker.executor:oci org.mobyproject.buildkit.worker.hostname:nuc org.mobyproject.buildkit.worker.snapshotter:overlayfs], platforms=[linux/amd64 linux/386] 
WARN[0000] skipping containerd worker, as "/run/containerd/containerd.sock" does not exist 
INFO[0000] found 1 workers, default="l1ltft74h0ek1718gitwghjxy" 
WARN[0000] currently, only the default worker can be used. 
INFO[0000] running server on /run/buildkit/buildkitd.sock 

现在我们开始构建,并将配置文件的位置作为构建上下文传给它。我们需要 buildctl 命令,buildctl 是守护进程的一个客户端,它将指定如何构建镜像以及在构建完成后应该做什么,比如导成 tar、忽略构建或将其推送到注册表。

buildctl build --help
NAME:
   buildctl build - build


USAGE:
   
  To build and push an image using Dockerfile:
    $ buildctl build --frontend dockerfile.v0 --opt target=foo --opt build-arg:foo=bar --local context=. --local dockerfile=. --output type=image,name=docker.io/username/image,push=true
  


OPTIONS:
   --output value, -o value  Define exports for build result, e.g. --output type=image,name=docker.io/username/image,push=true
   --progress value          Set type of progress (auto, plain, tty). Use plain to show container output (default: "auto")
   --trace value             Path to trace file. Defaults to no tracing.
   --local value             Allow build access to the local directory
   --frontend value          Define frontend used for build
   --opt value               Define custom options for frontend, e.g. --opt target=foo --opt build-arg:foo=bar
   --no-cache                Disable cache for all the vertices
   --export-cache value      Export build cache, e.g. --export-cache type=registry,ref=example.com/foo/bar, or --export-cache type=local,dest=path/to/dir
   --import-cache value      Import build cache, e.g. --import-cache type=registry,ref=example.com/foo/bar, or --import-cache type=local,src=path/to/dir
   --secret value            Secret value exposed to the build. Format id=secretname,src=filepath
   --allow value             Allow extra privileged entitlement, e.g. network.host, security.insecure
   --ssh value               Allow forwarding SSH agent to the builder. Format default|<id>[=<socket>|<key>[,<key>]]

我使用下面的命令获得与 Docker 命令等价的效果:

sudo -E buildctl build --frontend dockerfile.v0 
 --local context=./build/build-test/ 
 --local dockerfile=./build/build-test/ 
 --output type=image,name=docker.io/alexellis2/build-test:latest,push=true

在运行这个命令之前,你需要先运行 docker login,或者使用一组有效的未加密凭证来创建 $HOME/.docker/config.json 文件。

不用Docker也能构建容器的4种方法

 

使用 img 和 buildkit 构建

由于我从未使用过 img,也没有听说有团队在大规模使用它,所以我想要尝试一下。

首先它不支持多平台架构,armhf 和 ARM64 平台没有对应的二进制文件,而且项目年龄不算短了,所以不太可能会提供多平台支持。

x86_64平台的最新版本是 2019 年 5 月 7 号的 v0.5.7,使用 Go 1.11 构建:

sudo curl -fSL "https://github.com/genuinetools/img/releases/download/v0.5.7/img-linux-amd64" -o "/usr/local/bin/img" 
	&& sudo chmod a+x "/usr/local/bin/img"

它的构建选项就像是 buildctl 的一个子集

img build --help
Usage: img build [OPTIONS] PATH


Build an image from a Dockerfile.


Flags:


  -b, --backend  backend for snapshots ([auto native overlayfs]) (default: auto)
  --build-arg    Set build-time variables (default: [])
  -d, --debug    enable debug logging (default: false)
  -f, --file     Name of the Dockerfile (Default is 'PATH/Dockerfile') (default: <none>)
  --label        Set metadata for an image (default: [])
  --no-cache     Do not use cache when building the image (default: false)
  --no-console   Use non-console progress UI (default: false)
  --platform     Set platforms for which the image should be built (default: [])
  -s, --state    directory to hold the global state (default: /home/alex/.local/share/img)
  -t, --tag      Name and optionally a tag in the 'name:tag' format (default: [])
  --target       Set the target build stage to build (default: <none>)

要构建一个镜像需要做这些事情:

sudo img build -f ./build/build-test/Dockerfile -t alexellis2/build-test:latest ./build/build-test/

由于这样或那样的原因,img 实际上没能构建成功。可能是因为试图以非 root 用户身份进行一些优化。

不用Docker也能构建容器的4种方法

 

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0xe5 pc=0x7f84d067c420]


runtime stack:
runtime.throw(0xfa127f, 0x2a)
	/home/travis/.gimme/versions/go1.11.10.linux.amd64/src/runtime/panic.go:608 +0x72
runtime.sigpanic()
	/home/travis/.gimme/versions/go1.11.10.linux.amd64/src/runtime/signal_unix.go:374 +0x2f2


goroutine 529 [syscall]:
runtime.cgocall(0xc9d980, 0xc00072d7d8, 0x29)
	/home/travis/.gimme/versions/go1.11.10.linux.amd64/src/runtime/cgocall.go:128 +0x5e fp=0xc00072d7a0 sp=0xc00072d768 pc=0x4039ee
os/user._Cfunc_mygetgrgid_r(0x2a, 0xc000232260, 0x7f84a40008c0, 0x400, 0xc0004ba198, 0xc000000000)

似乎已经存在三个类似的问题。

使用 Kaniko 构建

Kaniko 是谷歌的容器构建器,旨在为容器构建提供沙箱。你可以将其作为一次性容器,也可以将其作为独立的二进制文件。

docker run -v $PWD/build/build-test:/workspace 
 -v ~/.docker/config.json:/kaniko/config.json 
 --env DOCKER_CONFIG=/kaniko 
 gcr.io/kaniko-project/executor:latest 
 -d alexellis2/build-test:latest
  • -d指定在成功构建后应该将镜像放在哪里。
  • -v将当前目录挂载到Kaniko容器中,还添加了config.json配置文件,指定将镜像推送到哪个远程注册表。
不用Docker也能构建容器的4种方法

 

Kaniko 提供了缓存支持,但需要手动管理和保存,因为 Kaniko 是在一次性模式下运行的,不像 Buildkit 那样是守护进程。

以上各种工具的总结

  • Docker——传统的构建器

安装 Docker 是个“大工程”,可能会给你的系统带来比预想的要多得多的东西。Docker 构建器是最古老的,也是最慢的。要注意在安装 Docker 时附带安装的网桥,它可能会与使用相同私有 IP 段的其他私有网络发生冲突。

  • Docker——与buildkit一起

这是最快的工具选择,改动最少,只需要加个DOCKER_BUILDKIT=1就可以启用。

  • 单独的buildkit

这个选项非常适合集群内构建,或者不需要 Docker 的系统(如 CI 或执行器)。它需要 Linux 主机,在 MacOS 上的使用体验太差,或许可以运行一个额外的 VM 或主机,然后通过 TCP 来访问?

  • Kaniko

使用 Kaniko 仍然需要安装 Docker,但不管怎样,它毕竟提供了另一种选择。

全文总结

你可以在 OpenFaaS 中使用普通的容器构建器,也可以使用 faas-cli build --shrinkwrap,并将构建上下文传给首选工具。

下面是使用相应工具构建 OpenFaaS 容器的示例:

  • 谷歌云构建
  • GitHub Actions
  • Jenkins
  • GitLab CI

在 OpenFaaS 云上,我们使用本文介绍的上下文传递方法和 buildkit 守护进程提供了完全不需要人工干预的 CI/CD 构建体验。对于其他用户,我建议使用 Docker,或者带有 buildkit 的 Docker。

你可以使用 GitHub 或 GitLab 集成构建自托管的 OpenFaaS 云环境。

对于 faasd 用户,你的主机上只安装了 containerd,而没有安装 docker,所以最好的选择是下载 buildkit。

原文链接:

https://blog.alexellis.io/building-containers-without-docker/



Tags:容器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一般的docker镜像为了节省空间,通常是没有安装systemd或者sysvint这类初始化系统的进程。一旦容器的起始进程不稳定将会产生大量的僵尸进程,影响宿主系统的运行。 缺少init的...【详细内容】
2021-12-23  Tags: 容器  点击:(6)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Tags: 容器  点击:(33)  评论:(0)  加入收藏
今天不做保姆级教程,分享奶爸常用、好用的Docker应用。有了这些Docker,Nas的可玩性会大幅提高,有时候奶爸也在想,刨去官方套件不考虑的话,Nas真的是差不多。如果小伙伴们有需要,后...【详细内容】
2021-09-03  Tags: 容器  点击:(167)  评论:(0)  加入收藏
概述谷歌云使用先进的 Andromeda 网络来实现 VPC 内实例之间的相互访问,以及 Google Kubernetes Engine (GKE) 的 Pod 的跨节点互访,避免了配置静态路由或者 Overlay 网络带来...【详细内容】
2021-08-20  Tags: 容器  点击:(103)  评论:(0)  加入收藏
stack容器#include <iostream>using namespace std;#include <stack>//容器头文件void test(){stack<int>p;p.push(100);p.push(1000);p.push(100);while(!p.empty()){cout<...【详细内容】
2021-08-17  Tags: 容器  点击:(81)  评论:(0)  加入收藏
一、介绍    1、介绍        最近无聊,也没什么事做,没事做总是要给自己找点事情做吧,毕竟人的生活在与折腾。于是,决定自己手动写一个 IOC 的框架。我们知道在 Net...【详细内容】
2021-07-20  Tags: 容器  点击:(80)  评论:(0)  加入收藏
环境:Spring5.3.3Spring容器启动时,创建 DefaultListableBeanFactory 工厂实例化 AnnotationConfigApplicationContext对象public AnnotationConfigApplicationContext(String...【详细内容】
2021-06-10  Tags: 容器  点击:(152)  评论:(0)  加入收藏
对于初学者来说,刚刚接触docker会有点迷,特别是镜像与容器。其实我们可以理解镜像与容器为一对多的关系。下图错误的示范,为什么是错误的呢?因为可以通过一个镜像确实可以启动...【详细内容】
2021-06-09  Tags: 容器  点击:(136)  评论:(0)  加入收藏
前言最近在工作中,接手了不少历史遗留的项目,有一些依赖是使用的docker启动,可以正常使用。但是由于优化服务器资源的缘故,需要将这些依赖迁移到其他服务器,这时候问题出现了。此...【详细内容】
2021-06-02  Tags: 容器  点击:(254)  评论:(0)  加入收藏
虚拟节点(Virtual Node)实现了Kubernetes与弹性容器实例ECI的无缝连接,让Kubernetes集群轻松获得极大的弹性能力,而不必受限于集群的节点计算容量。您可以灵活动态的按需创建ECI...【详细内容】
2021-04-15  Tags: 容器  点击:(231)  评论:(0)  加入收藏
▌简易百科推荐
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  实战Java    Tags:Docker   点击:(10)  评论:(0)  加入收藏
在网页中渲染公式一直是泛学术工具绕不开的一个功能,最近更新产品功能,正巧遇到了这个需求,于是使用容器方式简单实现了一个相对靠谱的公式渲染服务。分享出来,希望能够帮到有类...【详细内容】
2021-12-01  编程菌zfn    Tags:Docker   点击:(10)  评论:(0)  加入收藏
1.1 docker命令直接部署1.1.1 拉取镜像docker pull wurstmeister/zookeeperdocker pull wurstmeister/kafka1.1.2 启动zookeeper容器docker run -d --name myzookeeper -p 2...【详细内容】
2021-11-15  无    Tags:docker   点击:(47)  评论:(0)  加入收藏
01 前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述我们在docker中使用浏览器进行自动化测试如果可以...【详细内容】
2021-10-29  小码哥聊软件测试    Tags:Docker   点击:(42)  评论:(0)  加入收藏
因为你懂得的原因,下载docker镜像速度非常喜感,故收集几个国内常用的docker镜像。Docker中国区官方镜像地址:https://registry.docker-cn.com网易163的镜像http://hub-mirror.c...【详细内容】
2021-10-28  抓蛙程序猿    Tags:docker   点击:(48)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Java网络研发架构师    Tags:Spring   点击:(33)  评论:(0)  加入收藏
我们在很多场景下都需要做笔记,来对抗遗忘,一份好的笔记不仅能在需要的时候供我们查阅,也能帮助我们归纳整理知识提高做事效率。 目前市面上有很多云笔记软件,体验上各有不同,但...【详细内容】
2021-10-11  运维贼船    Tags:docker   点击:(61)  评论:(0)  加入收藏
1. Nacos官网Nacos Docker 快速开始2. Clone 项目git clone https://github.com/nacos-group/nacos-docker.git3. cd 到nacos-docker 路径下 直接启动即可cd nacos-dockerdo...【详细内容】
2021-09-16  程序狗爱化妆    Tags:Nacos   点击:(109)  评论:(0)  加入收藏
今天不做保姆级教程,分享奶爸常用、好用的Docker应用。有了这些Docker,Nas的可玩性会大幅提高,有时候奶爸也在想,刨去官方套件不考虑的话,Nas真的是差不多。如果小伙伴们有需要,后...【详细内容】
2021-09-03  晋升奶爸的垃圾佬    Tags:Docker   点击:(167)  评论:(0)  加入收藏
环境要求 ubuntu系统:20.04 docker版本:20.10.7 redis版本:6.0.6步骤由于我这里已经有相应的redis镜像,这里就不记录了,关于docker一些基础知识可以看我以前的笔记开启3台re...【详细内容】
2021-07-26  石老师小跟班    Tags:Redis主从复制   点击:(117)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条