ども。最近ハイペースでブログ書いています。
先日ansible containerでがんばってdocker image作成する話を書きました。
Ansibleで管理している構成をdocker imageに固めたいという要件があったのでansible containerをやっていたのですが、これより良い方法があったので書いときます。
Packerとは
Packerとは、Hashicorp社が提供しているサービスです。
Modern, Automated
HashiCorp Packer is easy to use and automates the creation of any type of machine image. It embraces modern configuration management by encouraging you to use automated scripts to install and configure the software within your Packer-made images. Packer brings machine images into the modern age, unlocking untapped potential and opening new opportunities.
ちょっと前はAWSなんかのAMIを自動で作成したりというイメージだったのですが、Dockerがより普及してきてからはDocker imageをPackerで管理したりビルドしたりする人も増えてきたのかなと思います。
Packer + ansible
vagrantでansible使ったことがある人ならピンとくるかもしれないですね。
今回はansible-localを使ってコンテナそのものにansibleを実行させます。この方法がきれいなのかはちょっと審議(ansibleをインストールさせる手間があるから)
Ansible好きだしAnsibleで運用しているものが多いので、そいつでdocker imageに固められるなら結構よいです。
やってみる
いつもの通りローカル環境はMacbookです。
- packerインストール
% brew install packer
% packer version Packer v1.2.2
container.json
packerが読み込むファイルです。
ちなみにファイル名はなんでも良いです。
{ "builders": [{ "type": "docker", "image": "centos:7", "export_path": "image.tar" }], "provisioners":[{ "type": "shell", "inline": [ "yum -y update", "yum -y install epel-release", "yum -y install python-pip", "pip install --upgrade pip", "pip install ansible==2.5.0" ]}, { "type": "ansible-local", "playbook_file": "container_base.yml" }], "post-processors": [{ "type": "docker-import", "repository": "ansible-dockerimage", "tag": "0.1.0" }] }
ちょっと簡単に解説を入れておきます。
- builders:
どうビルドするか定義する箇所です。
・type
でdockerを指定することでdocker imageを扱える
・image
にはpullするベースとなるコンテナを指定
・export_path
はイメージを出力名
- provisioners:
イメージに対してどうプロビジョニングするか定義する箇所です。
・type
でプロビジョニングする方法を指定。今回はshellとAnsibleをそれぞれ指定
・ansible-local
でコンテナ自身にAnsibleを実行させる
- post-processors:
構築したイメージの後処理を定義する箇所です。
・docker imageとしてビルドするのでdocker-importを指定
container_base.yml
container.jsonに書かれたplaybook_file
部分に記述されたファイルの内容です。
同じくファイル名はなんでも良いですが、playbook_file
に記述されている名前とあわせましょう。
ちょっと挙動がみたいだけなので簡単なインストールだけにしておきました。
- hosts: all become: True tasks: - name: install package yum: name={{ item }} state=present with_items: - git - htop
ビルド
packerでビルドします。
% packer build container.json docker output will be in this color. ==> docker: Creating a temporary directory for sharing data... ==> docker: Pulling Docker image: centos:7 (略) docker: Collecting pip docker: Downloading pip-9.0.3-py2.py3-none-any.whl (1.4MB) docker: Installing collected packages: pip docker: Found existing installation: pip 8.1.2 docker: Uninstalling pip-8.1.2: docker: Successfully uninstalled pip-8.1.2 docker: Successfully installed pip-9.0.3 docker: Collecting ansible==2.5.0 (略) docker: docker: PLAY [all] ********************************************************************* docker: docker: TASK [Gathering Facts] ********************************************************* docker: ok: [127.0.0.1] docker: docker: TASK [install package] ********************************************************* docker: changed: [127.0.0.1] => (item=[u'git', u'htop']) docker: docker: PLAY RECAP ********************************************************************* docker: 127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 docker: ==> docker: Exporting the container ==> docker: Killing the container: xxxxxxxxxxxxxxx ==> docker: Running post-processor: docker-import docker (docker-import): Importing image: Container docker (docker-import): Repository: ansible-dockerimage:0.1.0 docker (docker-import): Imported ID: sha256xxxxxxxxxxxxxxxxx Build 'docker' finished. ==> Builds finished. The artifacts of successful builds are: --> docker: Imported Docker image: ansible-dockerimage:0.1.0
無事完了!
- docker imagesにあるか確認してみる
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ansible-dockerimage 0.1.0 6af5e04ddc32 25 minutes ago 467MB
(CREATEDのタイムが経過しているのはブログ執筆の関係です^^;)
ログインしてみる
% docker run -it 6af5e04ddc32 /bin/bash [root@8e9de3152e7e /]# [root@8e9de3152e7e /]# htop [root@8e9de3152e7e /]# git usage: git [--version] [--help] [-c name=value] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>] The most commonly used git commands are: add Add file contents to the index bisect Find by binary search the change that introduced a bug branch List, create, or delete branches checkout Checkout a branch or paths to the working tree clone Clone a repository into a new directory commit Record changes to the repository diff Show changes between commits, commit and working tree, etc fetch Download objects and refs from another repository grep Print lines matching a pattern init Create an empty Git repository or reinitialize an existing one log Show commit logs merge Join two or more development histories together mv Move or rename a file, a directory, or a symlink pull Fetch from and merge with another repository or a local branch push Update remote refs along with associated objects rebase Forward-port local commits to the updated upstream head reset Reset current HEAD to the specified state rm Remove files from the working tree and from the index show Show various types of objects status Show the working tree status tag Create, list, delete or verify a tag object signed with GPG 'git help -a' and 'git help -g' lists available subcommands and some concept guides. See 'git help <command>' or 'git help <concept>' to read about a specific subcommand or concept. [root@8e9de3152e7e /]#
インストールしたものが実行できましたね!
おわりに
実際に運用されているAnsibleはもっとごりごりに複雑なので、それぞれのコンテナにプロビジョニングする必要があります。
とはいえ、先日試行したansible containerとは比べ物にならないほど楽っすねw