2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ansibleを使ってEC2を自分用のyumリポジトリにする

Last updated at Posted at 2019-07-06

はじめに

Ansibleを使って1台のEC2をyumリポジトリサーバに構成して、これを使って2台目以降のEC2にRPMパッケージをインストールしました。

yumリポジトリを自作した目的

  • 重要なパッケージを検証済みのバージョンで揃えたい
  • インターネットに接続しないサーバにもパッケージをインストールしたい
  • 各サーバにパッケージをインストールする際のバージョン指定は全部「latest」とし、リポジトリに配置するパッケージでバージョンをコントロールしたい
  • 各サーバにリポジトリ設定を追加したくない

環境

使用した環境は以下のとおりですが、物理マシンにCentOSの環境でも特に違いはありません。

  • コントロールノード: AWS Cloud9
    Ansibleを実行するマシンです
  • ターゲットノード: AWS EC2 / Amazon Linux 2
    Ansibleで自動構成される対象ホストです

コントロールノード

Ansibleをインストールする必要があるノードはコントロールノードだけです。EPELからyumでインストールします。

sudo yum -y install epel-release  # AWS Cloud9はインストール済み
sudo yum -y install ansible

ターゲットノード

自動構成の対象となるターゲットノードに必要な追加ソフトウェアはありません。
必要な環境はPython 2.6以上か3.5以上だけなので Amazon Linux、CentOS 6 以上などがそのまま使用できます。

インベントリとプレイブックの構成

今回の規模ならもっと単純でもいいのですが、規模によって構成をあまり変えたくないので、公式のベストプラクティスになるべく準拠して以下の構成にしました。

参考: Best Practices — Ansible Documentation

ディレクトリ構成(全体)
.
├── inventories       # インベントリ用ディレクトリ
│   ├── development   # 開発環境用インベントリ(今回の対象)
│   ├── production    # 本番環境用インベントリ
│   └── staging       # ステージング環境用インベントリ
│
├── roles             # ロール用ディレクトリ
│   ├── common        # 共通ロール
│   ├── httpd         # HTTP Serverをインストールするロール
│   ├── openvpn       # OpenVPNをインストールするロール
│   └── repo          # リポジトリサーバを構成するロール
│
├── repo-servers.yml  # リポジトリサーバのグループ用プレイブック
├── site.yml          # マスタープレイブック
└── vpn-servers.yml   # VPNサーバのグループ用プレイブック

インベントリ

inventoriesディレクトリの直下は環境ごとのディレクトリで、開発環境、ステージング環境、本番環境用のディレクトリを用意しました。今回は開発環境用のdevelopmentだけを使用します。

inventories/
├── inventories
│   ├── development  # 開発環境用(今回の対象)
│   ├── production   # 本番環境用
│   └── staging      # ステージング環境用

developmentの下は以下のような構成になっています。

inventories/development/
├── inventories
│   ├── development
│   │   ├── group_vars      # グループごとの変数定義を格納するディレクトリ
│   │   │   └── all.yml     # グループ「all」(全体)用の変数定義ファイル
│   │   ├── host_vars       # ホストごとの変数定義を格納するディレクトリ
│   │   │   ├── repo-1.yml  # ホスト「repo-1」用の変数定義ファイル
│   │   │   └── vpn-1.yml   # ホスト「vpn-1」用の変数定義ファイル
│   │   └── hosts.yml       # 開発環境用のインベントリ定義ファイル

インベントリ定義ファイル

hosts.ymlでホストとグループの全体を定義します。
書籍などではiniファイル形式で解説されていることが多いようですが、ここではYAML形式を使用します。

inventories/development/hosts.yml
all:               # グループ「all」(全体)
  children:        # allの子グループ
    repo-servers:  # グループ「repo-servers」
      hosts:       # repo-serversに属するホスト
        repo-1     # yumリポジトリを構成するホスト
    vpn-servers:   # グループ「vpn-servers」
      hosts:       # vpn-serversに属するホスト
        vpn-1      # openvpnをインストールするホスト

allは全体を表す定義済みのグループ名です。今回はユーザー定義の子グループとしてrepo-serversvpn-serversの2つを定義し、それぞれにターゲットノードのrepo-1vpn-1を含めました。

グループ変数定義ファイル

group_varsディレクトリにはグループごとの変数定義ファイルを配置します。
今回は全ターゲットノードへのSSH接続に同じ秘密鍵を使用するので、全体用の変数としてall.ymlに定義しました。

inventories/development/group_vars/all.yml
ansible_ssh_private_key_file: ~/my-keypair.pem

ansible_ssh_private_key_fileは、SSH秘密鍵のパスを格納するための定義済み変数です。

ホスト変数定義ファイル

host_varsディレクトリにはホストごとの変数定義ファイルを配置します。
例えば以下のように定義済み変数ansible_hostに各ホストのIPアドレスを設定することで、「repo-1」「vpn-1」という名前で接続できるようになります。

inventories/development/host_vars/repo-1.yml
ansible_host: 172.16.1.4
inventories/development/host_vars/vpn-1.yml
ansible_host: 172.16.1.5

ロール

プレイブック内の処理を再利用しやすくするために、分割してロールとして定義します。例えば Apache HTTP Server をインストールするロールは、リポジトリサーバの他に Webサーバでもそのまま利用できます。

rolesディレクトリの下にユーザー定義のロール名でディレクトリを作ります。今回は以下の4つのロールを定義しました。

roles/
├── roles
│   ├── common    # 共通ロール
│   ├── httpd     # HTTP Serverをインストールするロール
│   ├── openvpn   # OpenVPNをインストールするロール
│   └── repo      # リポジトリサーバを構成するロール

参考: Roles — Ansible Documentation

共通ロール

共通ロールcommonは、全ターゲットノードに共通の構成のために作りました。
ロール名のディレクトリの下に、転送するファイルを格納するfilesとタスク定義ファイルを格納するtasksディレクトリを配置します。

roles/common/
├── roles
│   ├── common
│   │   ├── files        # ターゲットノードに転送するファイルを格納するディレクトリ
│   │   │   └── etc
│   │   │       ├── yum.repos.d
│   │   │       │   └── myrepo.repo
│   │   │       └── hosts
│   │   └── tasks        # タスク定義ファイルを格納するディレクトリ
│   │       └── main.yml

共通ロールのファイル

filesディレクトリの下はディレクトリ構成もファイル名も自由です。今回はターゲットノードに配置するパスのとおりに、/etc/yum.repos.d/myrepo.repo(リポジトリ設定ファイル)と/etc/hosts(ホスト名とIPアドレスの設定ファイル)を配置しました。

自作のリポジトリサーバを他のホストから利用できるようにするために、以下のリポジトリ設定ファイルを用意します。
yum-plugin-prioritiesがインストールされていれば、priorityに10より小さい値を設定することで標準設定のリポジトリよりも優先されるようになります。

roles/common/files/etc/yum.repos.d/myrepo.repo
[myrepo]
name=myrepo
baseurl=http://repo-1.local/repo/
priority=2
gpgcheck=0
enabled=0
report_instanceid=yes

他のホストがrepo-1.localという名前でリポジトリサーバに接続できるようにするために、以下の/etc/hostsファイルも用意します。DNSを使用する場合は不要です。

roles/common/files/etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost6 localhost6.localdomain6

172.16.1.4  repo-1.local

共通ロールのタスク

  1. copyモジュールを使用して、filesで用意した/etc/hostsファイルを転送して配置します
  2. copyモジュールを使用して、filesで用意したリポジトリ設定ファイルを転送して配置します
  3. yumモジュールを使用して、インターネットのリポジトリから指定のパッケージをインストールします
roles/common/tasks/main.yml
- name: Put hosts file
  copy:
    dest=/etc/hosts
    src=roles/common/files/etc/hosts
- name: Put repo file
  copy:
    dest=/etc/yum.repos.d/myrepo.repo
    src=roles/common/files/etc/yum.repos.d/myrepo.repo
- name: Install common packages
  yum:
    name="{{item}}"
    state=latest
  with_items:
    - yum-plugin-priorities
    - bash-completion

with_items:以下に定義したパッケージが順にインストールされます。
yum-plugin-prioritiesは自作リポジトリを全ホストに優先利用させるために必須のパッケージです(Amazon Linux 2にはデフォルトでインストールされていますが、必須であることをここで明示します)。

その他、全ホストにインストールしたいパッケージをここにいくつでも追加定義することができます。私はbash-completionが入っていないと耐えられないので追加しました。

各モジュールの公式ドキュメント:
copy – Copy files to remote locations
yum – Manages packages with the yum package manager

HTTP Serverロール

ロールhttpdはApache HTTP Serverをインストールするために定義しました。
ターゲットノードに転送するファイルはないので、tasksディレクトリだけを配置します。

roles/httpd/
├── roles
│   ├── httpd
│   │   └── tasks
│   │       └── main.yml

HTTP Serverロールのタスク

  1. yumモジュールを使用して、パッケージhttpdをインストールします
  2. serviceモジュールを使用して、サービスhttpdを起動状態にして自動実行にします
roles/httpd/tasks/main.yml
- name: Install HTTPD packages
  yum:
    name="{{item}}"
    state=latest
  with_items:
    - httpd
- name: Start and enable the service
  service:
    name=httpd
    state=started
    enabled=yes

各モジュールの公式ドキュメント:
yum – Manages packages with the yum package manager
service – Manage services

OpenVPNロール

ロールopenvpnはOpenVPNをインストールするために定義しました。

roles/openvpn/
├── roles
│   ├── openvpn
│   │   └── tasks
│   │       └── main.yml

OpenVPNロールのタスク

自作リポジトリmyrepoを有効化してopenvpnパッケージをインストールするだけです。

roles/openvpn/tasks/main.yml
- name: Install VPN packages
  yum:
    enablerepo=myrepo
    name="{{item}}"
    state=latest
  with_items:
    - openvpn

リポジトリロール

ロールrepoは共通ロールおよびHTTP Serverロールとの組み合わせで、リポジトリサーバを構成するためのロールです。
filestasksに加えて、タスクからの通知で実行されるハンドラを格納するためのhandlersディレクトリを持ちます。

roles/repo/
├── roles
│   └── repo
│       ├── files
│       │   └── var
│       │       └── www
│       │           └── html
│       │               └── repo
│       │                   └── Packages
│       │                       └── openvpn
│       │                           ├── lzo-2.06-8.amzn2.0.3.x86_64.rpm
│       │                           ├── openvpn-2.4.7-1.el7.x86_64.rpm
│       │                           └── pkcs11-helper-1.11-3.el7.x86_64.rpm
│       ├── handlers
│       │   └── main.yml
│       └── tasks
│           └── main.yml

リポジトリロールのファイル

yumリポジトリで公開するRPMパッケージファイルです。今回はOpenVPNと依存パッケージのみを配置します。HTTP Serverで公開するので、配置場所は/var/www/html/の下にします。

リポジトリロールのタスク

  1. yumモジュールを使用して、リポジトリデータベースを更新するためのコマンドcreaterepoをインストールします
  2. synchronizeモジュール(rsync)を使用して、RPMパッケージファイルをディレクトリごと/var/www/html/repo/に配置します
  3. ファイルが追加または変更されたら、通知packages changedを発行してハンドラを起動します。
roles/repo/tasks/main.yml
- name: Install commands for repository server
  yum:
    name="{{item}}"
    state=latest
  with_items:
    - createrepo
- name: Put repository packages
  synchronize:
    delete=yes
    dest=/var/www/html/repo/
    src=roles/repo/files/var/www/html/repo/Packages
  notify: "packages changed"

各モジュールの公式ドキュメント:
yum – Manages packages with the yum package manager
synchronize – A wrapper around rsync to make common tasks in your playbooks quick and easy

リポジトリロールのハンドラ

タスクからpackages changedが通知されたら、listen:でこの通知をリスニングしている以下のハンドラが実行されます。ここではcreaterepoコマンドを実行してリポジトリデータベースを更新します。

roles/repo/handlers/main.yml
- name: Run createrepo
  command: /usr/bin/createrepo /var/www/html/repo
  listen: "packages changed"

コマンドcreaterepo /var/www/html/repoを実行することで、指定のパスの直下にレポジトリデータベースが作成または更新されます。

createrepo未実行
var
└── www
    └── html
        └── repo
            └── Packages
                └── openvpn
                    ├── lzo-2.06-8.amzn2.0.3.x86_64.rpm
                    ├── openvpn-2.4.7-1.el7.x86_64.rpm
                    └── pkcs11-helper-1.11-3.el7.x86_64.rpm

/var/www/html/repo/repodata/にデータベースが作成されます。

createrepo実行後
var
└── www
    └── html
        └── repo
            ├── Packages
            │   └── openvpn
            │       ├── lzo-2.06-8.amzn2.0.3.x86_64.rpm
            │       ├── openvpn-2.4.7-1.el7.x86_64.rpm
            │       └── pkcs11-helper-1.11-3.el7.x86_64.rpm
            └── repodata
                ├── 4b2f....7463.xml.gz
                ├── 637d....275f.xml.gz
                ├── 6484....cacf-filelists.sqlite.bz2
                ├── e80e....9d8f-primary.sqlite.bz2
                ├── e9d8....df04-other.xml.gz
                ├── ffc4....ee24-other.sqlite.bz2
                └── repomd.xml

これで/var/www/html/repoがyumリポジトリになります。
/var/www/htmlはHTTP Serverのドキュメントルートなので、他のホストに対してhttp://ホスト名/repo/のURLでyumリポジトリを公開できるようになります。

プレイブック

リポジトリサーバのグループ用、VPNサーバのグループ用、およびそれら2つを順に実行するマスタープレイブックの、計3つのプレイブックを作成しました。

プレイブック
.
├── repo-servers.yml  # リポジトリサーバのグループ用
├── site.yml          # マスタープレイブック
└── vpn-servers.yml   # VPNサーバのグループ用

2つのホストグループはインベントリ定義ファイルで以下のように定義したので、repo-serversを対象としてansible-playbook を実行するとホストrepo-1が、vpn-servers対象として実行するとホストvpn-1が自動的に構成されます。

inventories/development/hosts.yml
    repo-servers:  # グループ「repo-servers」
      hosts:       # repo-serversに属するホスト
        repo-1     # yumリポジトリを構成するホスト
    vpn-servers:   # グループ「vpn-servers」
      hosts:       # vpn-serversに属するホスト
        vpn-1      # openvpnをインストールするホスト

repo-serversグループ用プレイブック

ターゲットノードでsudo を使用して、ロールをhttpdrepocommonの順に実行します。
このプレイブックが正常に終了すると自作のyumリポジトリが利用可能になります。

repo-servers.yml
- name: Deploy repo servers
  hosts: repo-servers
  become: yes
  roles:
    - httpd
    - repo
    - common

vpn-serversグループ用プレイブック

ターゲットノードでsudo を使用して、ロールをcommonopenvpnの順に実行します。
openvpnは自作リポジトリからパッケージを取得してインストールします。

vpn-servers.yml
- name: Deploy VPN servers
  hosts: vpn-servers
  become: yes
  roles:
    - common
    - openvpn

マスタープレイブック

上記2つのプレイブックを順に実行します。

site.yml
- import_playbook: repo-servers.yml
- import_playbook: backgate-servers.yml

プレイブックの実行

ansible-playbookコマンドの-iオプションでインベントリ定義ファイルを指定し、引数でマスタープレイブックを指定して実行します。
エラーが発生する場合は-vvvなどのオプションを追加して詳細を確認してください。

ansible-playbook -i inventories/development/hosts.yml site.yml

あとがき

Ansibleの進化が速いので、書籍などの情報がだんだん古くなっているようです。がんばって公式ドキュメントをもっと読もうと思います。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?