我试着使用ansible-bender构建了Nuxt.js的容器映像
背景 – 想得到的是一个中文版本的故事背景。
我以前使用Ansible的Docker模块在Ansible上完成了从构建Docker容器镜像到创建容器的任务。我尝试使用Ansible搭建了一个Nuxt.js的Docker容器。
当时我介绍了一款名为Ansible-Container的方便的容器管理工具,但是到了2020年,该工具已经停止开发。然而,随后出现了一款名为ansible-bender的新工具,它部分继承了Ansible Container的功能。
这次我想使用ansible-bender来构建容器镜像。
关于ansible-bender的内容
ansible-bender是一款可以使用Ansible Playbook构建容器镜像的工具。(https://github.com/ansible-community/ansible-bender)
在Docker模块中,我们通过在Playbook中指定Dockerfile的目标路径来构建容器镜像,而使用ansible-bender则可以直接在Playbook内部编写容器镜像的描述,从而实现容器镜像的构建。可以使用pip包管理工具进行安装。
必需条件
为了运行ansible-bender,需要先安装Podman和Buildah。我们在之前的文章中介绍了这些工具,如果您是第一次了解这些工具,请参考该文章。此外,在构建容器镜像时,需要一个已安装Python的基础镜像(不限于Python 2.x或3.x)。提前准备一个包含Python的最小容器镜像将会很方便。可以参考文章ansible-bender中关于创建容器镜像的内容。
FROM debian:buster
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3 && apt-get clean
构建容器镜像
一旦准备好ansible-bender,我们将开始构建容器镜像。在这里,我们将验证是否可以使用ansible-bender构建上一篇文章中构建的Nuxt.js容器镜像。
获取基础容器映像
FROM node:latest
WORKDIR /app
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3 && apt-get clean
为了使后续容器镜像构建更加轻松,选择以node镜像为基础而不是Debian容器作为基础镜像,因此安装了Python到node镜像以获取基础镜像。接下来将介绍目录结构。
├── Prototype
│ └── app/(Nuxt.jsのひな型)
└── build_nuxtimage.yml
尽管本文还是继承之前的内容,但变更之一是我们已经移除了Dockerfile。由于容器镜像的创建将使用build_nuxtimage.yml来完成,因此Dockerfile不再需要。为了比较,我们也将之前的Dockerfile内容附上。
FROM node:latest
ENV NUXT_HOST=0.0.0.0
ENV NUXT_TELEMETRY_DISABLED=1
WORKDIR /app
COPY ./app/package.json ./app/yarn.lock ./
RUN yarn install
COPY ./app .
CMD ["yarn", "run", "dev"]
将这个转换为ansible-bender的Playbook,将会得到以下结果。
---
- name: Build Nuxt.js image
hosts: all
gather_facts: false
vars:
ansible_python_interpreter: /usr/bin/python3
ansible_bender:
base_image: "localhost/node-python3"
ansible_extra_args: "-vvv"
target_image:
name: yuta28/bender-test
working_dir: /app
environment:
NUXT_HOST: 0.0.0.0
labels:
built-by: '{{ ansible_user }}'
cmd: "yarn run dev"
tasks:
- name: Copy Prototype parts
copy:
src: "{{ item }}"
dest: /app/
with_items:
- "{{ playbook_dir }}/Prototype/app/package.json"
- "{{ playbook_dir }}/Prototype/app/yarn.lock"
- name: Yarn install
command: "yarn install"
- name: Archive app directory
delegate_to: localhost
archive:
path: "{{ playbook_dir }}/Prototype/app"
dest: "{{ playbook_dir }}/Prototype/app.tar.gz"
format: gz
- name: Unpacks app.tar.gz
unarchive:
src: "{{ playbook_dir }}/Prototype/app.tar.gz"
dest: /
在Dockerfile中的RUN命令部分已经转换为了Playbook中的cmd变量,并创建了一个用于构建容器镜像的Playbook。基本上,我们将Dockerfile的指令写在任务中,但是由于Nuxt.js模板项目的复制使用了ansible的copy/synchronize命令,由于文件数量太多,处理无法完成。作为替代方案,我们使用了archive模块将模板项目的所有文件压缩,并在容器内展开。将使用ansible-bender命令来执行这个Playbook。
$ ansible-bender build build_nuxtimage.yml
ansible-playbook 2.9.13
config file = /tmp/ab_x4m8plk/ansible.cfg
configured module search path = ['/home/ec2-user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 3.6.8 (default, Dec 5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Using /tmp/ab_x4m8plk/ansible.cfg as config file
host_list declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
script declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
auto declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
Parsed /tmp/ab_x4m8plk/inventory inventory source with ini plugin
PLAYBOOK: .build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml *********************************************************************************************
1 plays in .build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml
PLAY [Build Nuxt.js image] ***********************************************************************************************************************************
META: ran handlers
TASK [Copy Prototype parts] **********************************************************************************************************************************
task path: /home/ec2-user/ansible-bender/simple-test/.build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml:5
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'mount', b'--', b'yuta28-bender-test-20200913-071934769597-cont']
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'( umask 77 && mkdir -p "` echo /tmp `"&& mkdir "` echo /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493 `" && echo ansible-tmp-1599981579.9843893-85539-240769061862493="` echo /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493 `" ) && sleep 0']
Using module file /usr/lib/python3.6/site-packages/ansible/modules/files/stat.py
<yuta28-bender-test-20200913-071934769597-cont> PUT /home/ec2-user/.ansible/tmp/ansible-local-85531c92iy6sw/tmptlan88hf TO /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'chmod u+x /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/ /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py && sleep 0']
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'/usr/bin/python3 /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py && sleep 0']
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
META: ran handlers
META: ran handlers
PLAY RECAP ***************************************************************************************************************************************************
yuta28-bender-test-20200913-071934769597-cont : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Getting image source signatures
Copying blob sha256:b323b70996e4f6d603c331669ac44cf6234a2e22002d3686e9c88398c6911c25
Copying blob sha256:e8847c2734e1bec913fbb00dbd638e9bff6c42f699bbeb897728e234cf1a6e72
Copying blob sha256:a4c504f73441d711e6e71e5c177a772efe4d500c2d97b2a1358ea65edc98e8d5
Copying blob sha256:ef5de533cb53783465669a60fc9b0b1c782d319c5c8991fe9868f3be8be8e58b
Copying blob sha256:cbe6bbd0c86ff46f87950e109e891445a085c9bbf5af737b0ae3871d782e5335
Copying blob sha256:174e334f3f463272eeba0021b8b2c54a8891abc0c74201bbd98e87e8c00524e2
Copying blob sha256:e404bec46f40991019fbf239256326c48afb7672768755740a6ba862d431e5c6
Copying blob sha256:58b4b808347b3cdc40003e905f03059f37ae8cf169e91ecf25250e475e27728f
Copying blob sha256:24a8e30559a7f9f31238761563cc4ab907863039cbc3778449ca8c55f50ecc4a
Copying blob sha256:9b6e6b48454d80e68f9709e8b82abfe7bd0d059464b9c1796d462601ea59182f
Copying blob sha256:9f9869f02922117d69ea1b18239a9d55ac8e6d4ca578fc7ef226d20c3e7424f2
Copying config sha256:ddcc7b1e45f6483f9df7f0d19a17969aa27f92f2e6f77962d3c87c29f32c8186
Writing manifest to image destination
Storing signatures
ddcc7b1e45f6483f9df7f0d19a17969aa27f92f2e6f77962d3c87c29f32c8186
Image 'yuta28/bender-test' was built successfully \o/
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/yuta28/bender-test latest ddcc7b1e45f6 32 minutes ago 1.41 GB
localhost/node-python3 latest 79003b61771b 3 hours ago 990 MB
由于创建了名为localhost/yuta28/bender-test的容器镜像,因此将启动容器。
$ podman run --rm -it -p 8080:3000 localhost/yuta28/bender-test:latest
yarn run v1.22.5
$ nuxt
WARN mode option is deprecated. You can safely remove it from nuxt.config 07:59:19
╭────────────────────────────────────────╮
│ │
│ Nuxt.js @ v2.14.5 │
│ │
│ ▸ Environment: development │
│ ▸ Rendering: server-side │
│ ▸ Target: server │
│ │
│ Listening: http://10.0.2.100:3000/ │
│ │
╰────────────────────────────────────────╯
ℹ Preparing project for development 07:59:21
ℹ Initial build may take a while 07:59:21
✔ Builder initialized 07:59:21
✔ Nuxt files generated 07:59:21
✔ Client
Compiled successfully in 8.21s
✔ Server
Compiled successfully in 6.60s
ℹ Waiting for file changes 07:59:30
ℹ Memory usage: 212 MB (RSS: 320 MB) 07:59:30
ℹ Listening on: http://10.0.2.100:3000/
您可以使用命令行工具在终端窗口输入”podman ps”以确认容器是否已启动。
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe83f066139c localhost/yuta28/bender-test:latest yarn run dev 12 minutes ago Up 12 minutes ago 0.0.0.0:8080->3000/tcp strange_moore
课题
我已经将Dockerfile转换为Playbook,并进行了容器镜像构建,但是在Dockerfile中能够实现的一些功能,在Playbook中却无法实现。
① 无法嵌入禁用数据收集请求的遥测设置
在Dockerfile中,我通过设置环境变量来进行这样的配置。
NUXT_TELEMETRY_DISABLED=1
这个设置是用来忽略Nuxt的统计信息收集请求的。默认情况下是启用的,当首次启动容器时会出现以下提示信息。
yarn run v1.22.5
$ nuxt
ℹ NuxtJS collects completely anonymous data about usage. 11:21:11
This will help us improving Nuxt developer experience over the time.
Read more on https://git.io/nuxt-telemetry
? Are you interested in participation? Yes ← Yes/Noで選択
由于每次启动时都被问到这个讨厌的问题,我想在设置中禁用它,于是将变量嵌入到了 Playbook 中,但是出现了以下错误导致失败。
$ ansible-bender build simple-test/build_nuxtimage.yml
There was an error during execution: variable /target_image/environment/NUXT_TELEMETRY_DISABLED is set to 1, which is not of type string
不确定具体原因,但可能是由于环境变量不是字符串类型而导致的错误。NUXT_TELEMETRY_DISABLED是布尔类型,但我不知道如何将布尔类型的环境变量添加到Playbook中。
解决方法是,在Nuxt.js的官方参考文档中介绍的方式中,将配置添加到app/nuxt.config.js中。
export default {
~~~~~末尾追加~~~~~
telemetry: false
}
②没有被使用的图像持续增加
在执行Playbook之后检查图像列表时会发现大量的none图像堆积在中间层。
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/yuta28/bender-test latest 3b568629853d 2 hours ago 1.41 GB
<none> <none> 30f38e724bd8 2 hours ago 1.41 GB
<none> <none> 2c3401135802 2 hours ago 1.41 GB
<none> <none> ab36ebfbcb82 2 hours ago 1.41 GB
<none> <none> 0c15be92f176 2 hours ago 992 MB
<none> <none> 0f4f0464e1e9 2 hours ago 992 MB
<none> <none> f19ac9e8da69 2 hours ago 991 MB
localhost/node-python3 latest 73bb42b858aa 5 days ago 991 MB
localhost/debian-python3 buster af956b4f0450 8 days ago 177 MB
由于大小为1GB的积累会给本地机器造成负担,因此我在创建后手动使用podman image prune进行删除,但在Dockerfile构建时未出现此问题,我不知道在Playbook内应添加什么设置才能解决。
对此的感受
就像上面提到的,與從Dockerfile進行構建相比,存在一些問題,從Ansible的Docker模塊中執行容器映像的構建更快。我認為在Playbook內完成容器映像的構建,而無需編寫Dockerfile是一個優點,但是我開始覺得還是應該編寫Dockerfile並從那裡進行構建指定好一些。
首先,我並沒有想到使用Ansible來進行容器管理的優點,docker-compose或Kubernetes更符合潮流,從實際操作上來看,我感到有些不安全。
如果有人理解使用ansible-bender進行容器管理的好處,請在評論區指出,謝謝。