🚀

GitHub Releaseに置いたインストーラをAnsibleで取得する方法

に公開

はじめに

AnsibleのPlaybookを運用している中で、インストーラやZIPファイルなどのバイナリをどう管理するかが課題になった。
当初は リポジトリ内のfiles/ に直接置いて管理していたが、気づけばリポジトリが数GBを超えるほど肥大化していた。
履歴を含めると clone に時間がかかる。

そこで「バイナリはGitの履歴に含めず、外部に保存・取得する方法」を検討し、GitHub Releasesを使ったバイナリ管理とAnsible連携の方法を試してみた。


GitHub Releasesを用いたバイナリ管理

GitHubには、リリースに紐づけて任意のファイル(最大2GB)をアップロードできる「Releases」機能がある。
GUIから簡単にZIPやインストーラを添付できる。

参考:

About releases - GitHub Docs


実装構成

以下のような構成で、GitHubのReleaseに登録したアセット(例: sample.zip)をAnsibleで取得する。

ディレクトリ構成

project-root/
├── inventory/
│   └── hosts.yml              # インベントリ
├── playbook.yml               # 呼び出し元Playbook
└── roles/
    ├── sample/
    │   └── tasks/
    │       └── main.yml       # package_assetを呼び出すタスク
    └── package_asset/
        └── tasks/
            └── main.yml       # GitHub Releaseからアセットを取得するタスク


Ansibleタスク例

roles/package_asset/tasks/main.yml

- name: Validate vars
  ansible.builtin.assert:
    that:
      - gh_repo is defined
      - gh_tag is defined
      - gh_asset is defined
      - gh_dest is defined
      - gh_token is defined

- name: Get release by tag (GitHub API)
  ansible.builtin.uri:
    url: "https://api.github.com/repos/{{ gh_repo }}/releases/tags/{{ gh_tag }}"
    headers:
      Authorization: "Bearer {{ gh_token }}"
      Accept: "application/vnd.github+json"
    return_content: true
  register: _rel

- name: Resolve asset id
  ansible.builtin.set_fact:
    gh_asset_id: "{{ (_rel.json.assets | selectattr('name','equalto', gh_asset) | first).id }}"
  failed_when: gh_asset_id is not defined

- name: Download asset (binary)
  ansible.builtin.get_url:
    url: "https://api.github.com/repos/{{ gh_repo }}/releases/assets/{{ gh_asset_id }}"
    headers:
      Authorization: "Bearer {{ gh_token }}"
      Accept: "application/octet-stream"
    dest: "{{ gh_dest }}"
    owner: "{{ gh_owner | default('root') }}"
    group: "{{ gh_group | default('root') }}"
    mode: "{{ gh_mode | default('0644') }}"
    force: false
    timeout: "{{ gh_timeout | default(120) }}"
    checksum: "{{ gh_checksum | default(omit) }}"

呼び出し側 roles/sample/tasks/main.yml

- name: Fetch package asset (GitHub private)
  import_role:
    name: gh_release_asset
  vars:
    gh_repo: your-org/your-repo
    gh_tag: v1.0.0
    gh_asset: sample.zip
    gh_dest: /work/sample.zip
    gh_token: "{{ lookup('env', 'GITHUB_TOKEN') }}"
  become: true

この構成により、GitHub APIを通じて指定のリリースからアセットをダウンロードできる。
Ansibleの copy モジュールを使う感覚で、外部バイナリを任意のディレクトリに配置できるのがポイントだ。


動作確認

ansible-playbook -i inventory/hosts.yml playbook.yml 

出力結果の一部:

TASK [gh_release_asset : Download asset (binary)] ******************************
changed: [target_node]

TASK [sample : List files in /work] ********************************************
changed: [target_node]

TASK [sample :  Show listing] ********************************************
ok: [target_node] => {
    "work_ls.stdout_lines": [
        "total 20",
        "-rw-r--r-- 1 root root 11228 Oct 16 00:00 sample.zip"
    ]
}

GitHub Release上のアセットが /work 配下に正常に配置されていることが確認できた。


まとめ

  • バイナリをGitリポジトリに直接コミットすると、履歴が膨らんで管理しづらくなる
  • GitHub Releaseを使えば、バージョン単位でインストーラを管理しつつ、Ansible内で取得できる
  • 完全に万能ではないが、GitHub内で完結する点はシンプルで、用途によっては“使える”構成だと感じた。

もしGitLabを使っている場合は、同様の機能としてGeneric Package Registryも検討できる。
リリース管理+アクセス制御まで一貫して行えるため、より使いやすい印象だ。

📚 参考


Discussion