技術系

ubntu上でAnsibleを使ってミドルウェアの構成管理を行う

Ansibleを使用して、Ubuntu上で効率的なミドルウェア構成管理を行う方法を紹介します。

本記事では、Ansibleの基本的な概念から、実際にPlaybookを作成してDockerやTerraformのインストールを自動化する手順までを網羅します。

エージェントレスで簡単にインフラ管理を行うAnsibleの魅力と、実際の運用に役立つポイントを実例を交えて解説しています。

これからAnsibleを導入したい方や、Ubuntu環境での自動化に関心のある方に向けた内容となっています。

ubntuのバージョンや設定は以前の投稿の内容となりますので、参考にしていただければ幸いです。

Ansibleのインストールと動作確認

ubntuに以下のコマンドを実行してpython3とansibleをインストールする。

sudo apt update
sudo apt install -y python3 python3-pip
sudo apt install -y ansible

ansibleのバージョンを確認する。

ubntu@ubntu:~$ ansible --version
ansible [core 2.16.3]
  config file = None
  configured module search path = ['/home/ubntu/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/ubntu/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.3 (main, Feb  4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

Ansible の ping モジュールを使って、ローカルのホストにアクセスできるか確認する。

警告が出ているものの、イベントリを明示的に指定することでこの警告は消える。疎通自体は問題ない。pongと返ってきたら成功だ。

ubntu@ubntu:~$ ansible localhost -m ping --connection=local
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

イベントリファイルの作成も行う。

echo "localhost ansible_connection=local" > hosts

シンプルな Playbook を作って、パッケージのインストールができるか確認する。

- name: Test Playbook
  hosts: localhost
  become: yes
  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes

    - name: Install tree
      apt:
        name: tree
        state: present

playbookの実行を行う。-iでイベントリファイルの指定と--connectionの指定をすることで警告が出なくなる。

ubntu@ubntu:~$ sudo ansible-playbook -i localhost, test.yml

PLAY [Test Playbook] ***********************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Update apt cache] ********************************************************
changed: [localhost]

TASK [Install tree] ************************************************************
ok: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

playbookによりtreeがインストールされていることを確認する。

ubntu@ubntu:~$ tree --version
tree v2.1.1 © 1996 - 2023 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro

DockerとterraformをAnsibleでインストール

DockerとterraformをインストールするPlaybookの作成を行う。
新しいPlaybookファイル「install_docker_terraform.yml」を作成する。

---
- name: Install Docker and Terraform
  hosts: localhost
  become: yes  # root 権限で実行
  tasks:
    - name: Install required packages
      apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - software-properties-common
        state: present
        update_cache: yes
    # Docker のインストール
    - name: Add Docker GPG key
      apt_key:
        url: https://download.docker.com/linux/ubuntu/gpg
        state: present
    - name: Add Docker repository
      apt_repository:
        repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
        state: present
    - name: Install Docker
      apt:
        name: docker-ce
        state: present
        update_cache: yes
    - name: Start and enable Docker service
      systemd:
        name: docker
        enabled: yes
        state: started
    - name: Add current user to Docker group
      user:
        name: "{{ ansible_user_id }}"
        groups: docker
        append: yes
    # Terraform のインストール
    - name: Add HashiCorp GPG key
      apt_key:
        url: https://apt.releases.hashicorp.com/gpg
        state: present
    - name: Add HashiCorp repository
      apt_repository:
        repo: "deb [arch=amd64] https://apt.releases.hashicorp.com {{ ansible_distribution_release }} main"
        state: present
    - name: Install Terraform
      apt:
        name: terraform
        state: present
        update_cache: yes

作成したカレントディレクトリ内で以下のコマンドを実行する。

カレントディレクトリに「install_docker_terraform.yml」が存在することを確認する。

ubntu@ubntu:~$ ls -la install_docker_terraform.yml 
-rw------- 1 ubntu ubntu 1601  3月  6 10:08 install_docker_terraform.yml

Playbookを実行する。

sudo ansible-playbook install_docker_terraform.yml

実行結果

ubntu@ubntu:~$ sudo ansible-playbook install_docker_terraform.yml
[sudo] ubntu のパスワード: 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'

PLAY [Install Docker and Terraform] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Install required packages] ***********************************************
changed: [localhost]

TASK [Add Docker GPG key] ******************************************************
changed: [localhost]

TASK [Add Docker repository] ***************************************************
changed: [localhost]

TASK [Install Docker] **********************************************************
changed: [localhost]

TASK [Start and enable Docker service] *****************************************
ok: [localhost]

TASK [Add current user to Docker group] ****************************************
changed: [localhost]

TASK [Add HashiCorp GPG key] ***************************************************
changed: [localhost]

TASK [Add HashiCorp repository] ************************************************
changed: [localhost]

TASK [Install Terraform] *******************************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=10   changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

警告は出ているが-i "localhost," --connection=localが入ってないからだろう。

-i "localhost," --connection=localを付けたところ警告が消えてすでに適応済みのためオールOKの結果となった。

ubntu@ubntu:~$ sudo ansible-playbook -i "localhost," --connection=local install_docker_terraform.yml

PLAY [Install Docker and Terraform] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Install required packages] ***********************************************
ok: [localhost]

TASK [Add Docker GPG key] ******************************************************
ok: [localhost]

TASK [Add Docker repository] ***************************************************
ok: [localhost]

TASK [Install Docker] **********************************************************
ok: [localhost]

TASK [Start and enable Docker service] *****************************************
ok: [localhost]

TASK [Add current user to Docker group] ****************************************
ok: [localhost]

TASK [Add HashiCorp GPG key] ***************************************************
ok: [localhost]

TASK [Add HashiCorp repository] ************************************************
ok: [localhost]

TASK [Install Terraform] *******************************************************
ok: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=10   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Playbook実行後の確認

dockerインストールの確認を行う。

ubntu@ubntu:~$ docker --version
Docker version 28.0.1, build 068a01e
ubntu@ubntu:~$ sudo systemctl status docker
[sudo] ubntu のパスワード: 
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-03-06 10:16:01 JST; 4h 7min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 9292 (dockerd)
      Tasks: 9
     Memory: 20.7M (peak: 21.5M)
        CPU: 2.603s
     CGroup: /system.slice/docker.service
             └─9292 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

 3月 06 10:16:00 ubntu dockerd[9292]: time="2025-03-06T10:16:00.837570637+09:00" level=info msg="OTEL tracing is not configured, using no-op tracer provider"
 3月 06 10:16:00 ubntu dockerd[9292]: time="2025-03-06T10:16:00.837742144+09:00" level=info msg="detected 127.0.0.53 nameserver, assuming systemd-resolved, >
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:00.997428634+09:00" level=info msg="Loading containers: start."
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.752933785+09:00" level=info msg="Loading containers: done."
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.830289688+09:00" level=info msg="Docker daemon" commit=bbd0a17 containerd-snapshotter=false >
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.830704688+09:00" level=info msg="Initializing buildkit"
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.904111672+09:00" level=info msg="Completed buildkit initialization"
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.914128754+09:00" level=info msg="Daemon has completed initialization"
 3月 06 10:16:01 ubntu dockerd[9292]: time="2025-03-06T10:16:01.914247463+09:00" level=info msg="API listen on /run/docker.sock"
 3月 06 10:16:01 ubntu systemd[1]: Started docker.service - Docker Application Container Engine.

dockerはversion 28.0.1でインストールされて現在動いている状態のようだ。自動起動も有効になっている。

terraformのインストールの確認も行う。

ubntu@ubntu:~$ terraform version
Terraform v1.11.1
on linux_amd64

terraformも無事インストールされていることが確認できた。

Playbook解説

install_docker_terraform.ymlの中身を見ていきたい。

Install required packages

- name: Install required packages
  apt:
    name:
      - apt-transport-https
      - ca-certificates
      - curl
      - software-properties-common
    state: present
    update_cache: yes

この処理はDockerやTerraformをインストールする前に必要なパッケージを準備するものとなる。

各パッケージの役割

パッケージ名役割
apt-transport-httpsapt で HTTPS を利用できるようにする
ca-certificates信頼された SSL/TLS 証明書を提供
curlHTTP リクエストを送るツール(GPGキー取得などに必要)
software-properties-commonapt-add-repositoryコマンドを提供

これらのパッケージがないと、リポジトリの追加や HTTPS でのダウンロードができないため、事前にインストールしておく。

httpsを使うことで、通信を暗号化し中間者攻撃のリスクを回避する。

{{ ansible_user_id }}

- name: Add current user to Docker group
  user:
    name: "{{ ansible_user_id }}"
    groups: docker
    append: yes

{{ ansible_user_id }}の意味は何か。

この変数はAnsibleのsetupモジュールで自動取得され、このPlaybookを実行したログイン名(実行ユーザ)を{{ ansible_user_id }}で取得し、そのユーザをdockerグループに追加している。

/etc/groupを確認したところrootがdockerグループに所属している。sudoによりrootで実行したためだ。

ubntu@ubntu:~$ cat /etc/group | grep docker
docker:x:986:root

🔹 何をしているのか?

  • Docker は root または docker グループのユーザーしか操作できないため、実行ユーザーを docker グループに追加。
  • append: yes により、既存のグループに影響を与えずに docker グループを追加。

🔹 どこから取得しているのか?

  • Ansible の setup モジュールで取得(Playbook 実行時に自動で取得される)
  • 環境変数 whoami のようなもの

append: yes

append: yesを書かないとどうなるか。

もしappend: yesを書かないとgroupで指定したグループ以外の所属が消えてしまう可能性がある。

例えば、以下のように実行した場合にはubntuユーザの既存グループはdockerだけになってしまう。具体的な挙動例については後述するので確認してほしい。

- name: Add user to docker group (without append)
  user:
    name: "ubntu"
    groups: docker

例1append no

ユーザーの元のグループ

$ groups ubntu
ubntu : ubntu sudo developers

append: no(デフォルト)で docker グループを設定

- name: Add user to docker group (without append)
  user:
    name: "ubntu"
    groups: docker  # append: yes がない

実行後のグループ

$ groups ubntu
ubntu : docker  # 他のグループが消えてしまった!

例2 append yes

ユーザーの元のグループ

$ groups ubntu
ubntu : ubntu sudo developers

append: yes で docker グループを追加

- name: Add user to docker group
  user:
    name: "ubntu"
    groups: docker
    append: yes

実行後

$ groups ubntu
ubntu : ubntu sudo developers docker

GPG キー & リポジトリ追加

- name: Add Docker GPG key
  apt_key:
    url: https://download.docker.com/linux/ubuntu/gpg
    state: present

- name: Add Docker repository
  apt_repository:
    repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
    state: present

GPGキー追加

https://download.docker.com/linux/ubuntu/gpg を取得し、信頼する鍵として登録

🔹 GPG キーとは?

  • 各パッケージ(Docker や Terraform)の提供元が 信頼できる ことを保証するための 署名キー
  • これを登録しないと、apt でのインストール時に「信頼できないリポジトリ」と見なされ、エラーが発生する

リポジトリ追加

  • deb [arch=amd64] https://download.docker.com/linux/ubuntu noble stable のようなリポジトリを /etc/apt/sources.list.d/ に追加
  • {{ ansible_distribution_release }} は、Ubuntu の バージョン名(例: focal, jammy, noble) を自動取得して設定

{{ ansible_distribution_release }}はAnsibleの組み込み変数で、現在の Ubuntu のコードネーム(例: focal, jammy, noble)が格納される。

この変数を利用することで、Ubntuのバージョン毎に異なるリポジトリを指定することができ、どのUbntuからでもPlaybookが本用的に動作する。(ハードコーディング不要)

🔹リポジトリ追加とは?

  • Ubuntu の apt は デフォルトのリポジトリ に含まれていないソフトウェアを扱えない
  • 公式リポジトリを追加することで、Docker や Terraform の最新バージョンを apt install で取得可能になる。

インストールされるミドルウェアのバージョンについて

🔹 実行時の最新バージョン

apt:
  name: docker-ce
  state: present
  update_cache: yes
  • state: present の場合 → 実行時点で利用可能な 最新バージョン がインストールされる
  • update_cache: yes で apt update を事前に実行し、最新リストを取得

バージョンを固定する場合には、特定のバージョンを指定すると、Playbook実行時に指定したバージョン以降の更新はされない。

apt:
  name: docker-ce=5:24.0.5-1~ubuntu.22.04~jammy
  state: present

バージョン管理

今後のバージョンアップの方針としては以下となる。

  • 手動アップグレード: sudo apt update && sudo apt upgrade
  • Ansible で管理: state: latest にすると毎回最新バージョンにアップデート可能

ただし、state: latest は予期しないバージョン変更が発生するため、慎重に運用すること!

state: latest と state: present + update_cache: yes の違い

state: latest の動作
- name: Install the latest version of a package
  apt:
    name: docker.io
    state: latest

何が起きるのか?

  • docker.io パッケージを 最新バージョン にアップグレードする
  • すでに最新バージョンなら何もしない
  • バージョンの更新 (apt update) を自動で実行する

🔹 ポイント

  • 明示的に update_cache: yes を書かなくてもOK
  • 既にインストールされている場合でも、より新しいバージョンがあればアップグレード される
state: present + update_cache: yes の動作

何が起きるのか?

  • apt updateを実行し、パッケージリストを最新化する
  • docker.io が インストールされていなければインストールする
  • しかし、すでにインストール済みなら何もしない(アップグレードはしない)

🔹 ポイント

  • アップグレードはしない(古いバージョンがあってもそのまま)
  • update_cache: yesを指定しないと、リポジトリ情報が古い可能性がある
state: latest vs state: present + update_cache: yes
方法apt updateapt upgrade の実行具体的な挙動
state: latest✅ 自動✅ 新バージョンがあればアップグレード既存パッケージも最新化
state: present + update_cache: yes✅ 明示的に実行❌ アップグレードなし古いバージョンのまま

Ansibleは昔使っていたことはありましたが、だいぶ忘れていたので、いい勉強になりました。

-技術系