使用Packer制作Docker镜像

使用Docker非常方便。
当我们不想在主机上弄乱机器时,虽然不至于太夸张,但通过Docker运行容器非常方便。

为了使用Docker,我们需要一个镜像,而默认情况下可以使用 Dockerfile 进行配置。但如果可以的话,最好使用最近流行的专用工具Ansible来进行配置。(因为可以共享playbook)。如果使用由Vagrant知名公司HashiCorp发布的Packer,就可以实现这一点。

Pakcer是什么?

Packer不仅仅是Docker,还专门用于创建用于虚拟容器的映像的自动执行工具。

    • EC2 (AMI)

 

    • Azre

 

    • DigitalOcan

 

    • Docker

 

    • Google Compute Engine

 

    • OpenStack

 

    • Parallels

 

    • QEMU

 

    • VirtualBox

 

    VMware

几乎所有虚拟化容器都能被支持。

需要的东西

只需要从下载页面安装软件包就可以了。

使用方法 (shǐ fǎ)

我們將創建一個包含有關如何建立映像的Packer設置文件(json)。

設定文件由以下三個部分組成。

    • builders: どの仮想コンテナ用のコンテナを作成するか。

 

    • provisioners: どうプロビジョニングするか。

 

    post-processors: 作成したイメージをどうするか?
{
    "builders":[
        ...
    ],

    "provisioners":[
        ...
    ],

    "post-processors": [
        ...
    ]
}

每个部分都可以指定多个项目。

建筑商部分

{
    "builders":[{
        "type": "docker",
        "image": "basebox/common:0.1",
        "export_path": "controller.tar",
        "pull": false
    }]
}

这次我们将创建一个Docker镜像,因此在type字段中指定”docker”,并将基础镜像的名称指定为image字段。
export_path字段用于指定用于临时保存镜像的文件名,但最后会自动删除,所以只需指定一个任意的名称即可。

如果使用本地存储库的镜像,则需要指定 pull: false。

提供者部分的部分

这个类型指定了要使用什么样的配置器。

在ansible的情况下,可以指定以下两种类型。

    • ansible-local: イメージ内に既にインストールされているansibleを使って、自分自身に対してプロビジョニングする。

 

    • ansible: 対象イメージにsshでリモート接続してプロビジョニングする。(通常のansibleと同じ)

EC2などはこちらを使う。

{
    "provisioners":[{
        "type": "shell",
        "inline": [
            "apt-get -y update",
            "apt-get install -y --no-install-recommends ansible",
            "mkdir -p /tmp/ansible-local"
        ]
    }, {
        "type": "file",
        "source": "files",
        "destination": "/tmp/ansible-local"
    }, {
        "type": "ansible-local",
        "playbook_file": "playbook.yml",
        "staging_directory": "/tmp/ansible-local"
    }]
}

这次我们将使用前者的ansible-local方法。
因此,在ansible(-local)提供者之前,我们需要放置一个shell提供者来安装ansible。

此外,为了在ansible中使用copy模块,需要在镜像内创建一个保存目标文件的目录(/tmp/ansible-local),并通过file提供程序将文件传输到该目录。

如果准备工作做得足够充分,剩下的就会很简单了。
只需使用ansible(本地)配置管理工具,指定playbook即可。
ansible的清单文件将由packer自动生成。

后处理器部分 qì

{
    "post-processors": [{
        "type": "docker-import",
        "repository": "category/image",
        "tag": "0.1"
    }]
}

指定如何处理生成的映像。
这次我们决定使用”docker-import”将映像注册到本地。

最后的packer.json

{
    "builders":[{
        "type": "docker",
        "image": "basebox/common:0.1",
        "export_path": "controller.tar",
        "pull": false
    }],

    "provisioners":[{
        "type": "shell",
        "inline": [
            "apt-get -y update",
            "apt-get install -y --no-install-recommends ansible",
            "mkdir -p /tmp/ansible-local"
        ]
    }, {
        "type": "file",
        "source": "files",
        "destination": "/tmp/ansible-local"
    }, {
        "type": "ansible-local",
        "playbook_file": "playbook.yml",
        "staging_directory": "/tmp/ansible-local"
    }],

    "post-processors": [{
        "type": "docker-import",
        "repository": "category/image",
        "tag": "0.1"
    }]
}

运行Packer。

执行非常简单。

$packer build <ビルドファイル>.json

从容器的生成到自动进行配置和保存映像。

执行结果

$ packer build -on-error=abort packer.json
docker output will be in this color.

==> docker: Creating a temporary directory for sharing data...
==> docker: Pulling Docker image: ubuntu:16.10
    docker: 16.10: Pulling from library/ubuntu
    docker: Digest: sha256:063e14a48414f6e66ec0e6570ae0f846623e08ff9416b280f560898bac7e7e63
    docker: Status: Image is up to date for ubuntu:16.10
==> docker: Starting docker container...
    docker: Run command: docker run -v /Users/h_toda/.packer.d/tmp/packer-docker793412964:/packer-files -d -i -t ubuntu:16.10 /bin/bash
    docker: Container ID: dd34a7aeeba9a3371d6c7ba84a215b145afaaea5d013676d6d1111f5647f9f12
==> docker: Provisioning with shell script: /var/folders/d1/c3mwd9kn20vdng53mywr181xm5hflj/T/packer-shell812644666
    docker: Get:1 http://security.ubuntu.com/ubuntu yakkety-security InRelease [92.2 kB]
    docker: Get:2 http://archive.ubuntu.com/ubuntu yakkety InRelease [247 kB]
    docker: Get:3 http://security.ubuntu.com/ubuntu yakkety-security/universe Sources [3526 B]

(snip)

    docker: Setting up ansible (2.1.1.0-1) ...
    docker: Processing triggers for libc-bin (2.24-3ubuntu1) ...
    docker: Processing triggers for ca-certificates (20160104ubuntu1) ...
    docker: Updating certificates in /etc/ssl/certs...
    docker: 173 added, 0 removed; done.
    docker: Running hooks in /etc/ca-certificates/update.d...
    docker: done.
==> docker: Uploading files => /tmp/ansible-local
==> docker: Provisioning with Ansible...
    docker: Creating Ansible staging directory...
    docker: Creating directory: /tmp/ansible-local
    docker: Uploading main Playbook file...
    docker: Uploading inventory file...
    docker: Executing Ansible: cd /tmp/ansible-local && ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook /tmp/ansible-local/playbook.yml -c local -i /tmp/ansible-local/packer-provisioner-ansible-local607385102
    docker:
    docker: PLAY [all] *********************************************************************
    docker:
    docker: TASK [setup] *******************************************************************
    docker: ok: [127.0.0.1]
    docker:
    docker: TASK [debug] *******************************************************************
    docker: ok: [127.0.0.1] => {
    docker: "msg": "Hellow, World!"
    docker: }
    docker:
    docker: PLAY RECAP *********************************************************************
    docker: 127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0
    docker:
==> docker: Exporting the container
==> docker: Killing the container: dd34a7aeeba9a3371d6c7ba84a215b145afaaea5d013676d6d1111f5647f9f12
==> docker: Running post-processor: docker-import
    docker (docker-import): Importing image: Container
    docker (docker-import): Repository: test/test:0.1
    docker (docker-import): Imported ID: sha256:8421edb057bd9ca2bb8c33cba75979f0beb64476a957fb195c3d0b8b7927e67b
Build 'docker' finished.

调试方法

默认情况下,当Packer内部发生错误时,Docker容器会被删除,导致无法找出错误原因。如果添加-on-error=abort选项,容器将不会被删除,这样就可以使用docker exec进入容器中进行调查。

$packer build -on-error=abort <构建文件>.json

与Dockerfile相比的优点

在Dockerfile中,每个命令都会提交一个镜像。

删除上传后的图像中的文件也不会使其变小,所以没有必要这样做。

RUN apt-get update && \
    apt-get install <なんとか> && \
    apt-get remove <なんとか> && \
    rm -r <なんとか>

就像使用串联方式将每个命令使用“&&”连接起来,作为一个步骤执行的批处理技巧一样,但在Packer中,不需要担心这样的问题。

请注意

在启动Docker容器时,我们要启动bash。如果使用像Alpine Linux这样默认没有安装bash的镜像,则需要在run_command中指定替代的shell(/bin/sh)。

    "builders":[{
        "type": "docker",
        "image": "alpine:edge",
        "export_path": "controller.tar",
        "run_command": ["-d", "-i", "-t", "{{.Image}}", "/bin/sh"]
    }]

请参阅

    Pakcer ドキュメント
bannerAds