我试着使用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
9fb09283f27cc2f4bc21d7e1cf223b8a.png

课题

我已经将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進行容器管理的好處,請在評論區指出,謝謝。

广告
将在 10 秒后关闭
bannerAds