こんにちは。たかやまです。
今まで生粋のWindowsユーザでしたが、この度Macが支給(※Windows/Mac選べます)されたのでこれからのMac利用を見据えてAnsibleでMacを構築してみたいと思います。
今回はAnsible GalaxyでMac構築に良さげなRoleがあったので記事にしたいと思います。
Ansible Galaxyとは
Ansibleで利用できるRoleやCollections (module, plugin, roleをまとめた単位)を配布するコミュニティサイトです。
今回はこのAnsible Galaxyで配布されているgeerlingguy.macを使用してMacを構築してみます。
構成
- macOS 12.3.1 M1/16GB
- Homebrew 3.4.4
- Ansible-core 2.12.4/Ansible 5
Mac構築手順
Homebrewインストール
Ansibleはpipでインストールするのが公式推奨手順ですが、個別にpipをインストールしたりpath通したりするのが手間なため今回はHomebrewでインストールします。
そのため、まずはHomebrewをインストールします。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
インストール後、homebrewのpathを通す。 ※zshの場合
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/your_username/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
インストールできました。
% brew --version
Homebrew 3.4.5
Homebrew/homebrew-core (git revision 492433b71e4; last commit 2022-04-07)
Ansibleインストール
homebrewでansibleをインストールします。
brew install ansible
Ansibleもサクッとインストールできます。
% ansible --version
ansible [core 2.12.4]
config file = None
configured module search path = ['/Users/your_username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /opt/homebrew/Cellar/ansible/5.5.0/libexec/lib/python3.10/site-packages/ansible
ansible collection location = /Users/your_username/.ansible/collections:/usr/share/ansible/collections
executable location = /opt/homebrew/bin/ansible
python version = 3.10.2 (main, Feb 2 2022, 05:51:25) [Clang 13.0.0 (clang-1300.0.29.3)]
jinja version = 3.1.1
libyaml = True
Ansible Galaxyインストール
Ansible-Galaxyからgeerlingguy.macをインストールします。
ansible-galaxy collection install geerlingguy.mac
Ansible-Galaxyのパッケージはカレントディレクトリ配下の.ansible
にダウンロードされます。あとは後述のPlaybookの中でインストールしたRole指定することで利用可能となります。
% ansible-galaxy collection list
.
.
# /Users/your_username/.ansible/collections/ansible_collections
Collection Version
----------------- -------
community.general 4.7.0
geerlingguy.mac 1.4.0
Playbookの作成
先ほどインストールしたgeerlingguy.mac
は3つのRoleで構成されています。
作成するPlaybookには利用するRoleで参照される変数を定義していく形になります。
Role | 機能 |
---|---|
geerlingguy.mac.homebrew | homebrewを使ったソフトウェア管理をする |
geerlingguy.mac.mas | Mac App Storeのソフトウェアを管理する |
geerlingguy.mac.dock | dockのレイアウト管理をする |
Playbook(site.yml)の記述例は以下の通りです。
今回インストールしたRoleだけでセットアップする場合は、こちらのPlaybookだけ用意すれば大丈夫です。
site.yml
- hosts: localhost
connection: local
become_user: your_computename
gather_facts: false
vars:
ansible_machine: arm64 # arm64/x86_64を指定する。今回はM1 Macなのでarm64を指定
ansible_user_id: your_username # 実行ユーザID
ansible_user_gid: your_groupid # 実行ユーザのグループID
homebrew_cask_apps: # インストールしたいcaskアプリをリスト形式で指定
- 1password
homebrew_cask_uninstalled_apps: # アンインストールしたいcaskアプリをリスト形式で指定
- alfred
homebrew_installed_packages: # インストールしたいGUIアプリをリスト形式で指定
- awscli
homebrew_uninstalled_packages: # アンインストールしたいGUIアプリをリスト形式で指定
- autoconf
mas_installed_apps: # インストールしたいMac Apple Storeアプリをリスト形式で指定
- { id: 409183694, name: "Keynote" }
mas_uninstalled_apps: # アンインストールしたいMac Apple Storeアプリをリスト形式で指定
- { id: 682658836, name: "GarageBand" }
dockitems_persist: # Dockの配列を指定
- name: Launchpad
path: "/Applications/Launchpad.app/"
pos: 1
roles: # インストールしたRoleを指定
- role: geerlingguy.mac.homebrew
tags: homebrew
- role: geerlingguy.mac.mas
tags: mas
- role: geerlingguy.mac.dock
tags: dock
ここに定義した変数以外にBrewfileを使ったインストール方法など他にも変数が用意されているので、気になった方はドキュメントをご確認ください。
Playbookの実行
以下のコマンドを実行することで、先ほど定義したPlaybook(site.yml)を元にRoleを読み込んでMacのセットアップをしてくれます。
ansible-playbook -i localhost, -c local site.yml
実行例(クリックで展開)
% ansible-playbook -i localhost, -c local site.yml
PLAY [localhost] ***********************************************************************************************************************************************
TASK [geerlingguy.mac.homebrew : Determine Homebrew ownership variables] ***************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure Homebrew parent directory has correct permissions (M1).] ***************************************************************
[WARNING]: Platform darwin on host localhost is using the discovered Python interpreter at /opt/homebrew/bin/python3.9, but future installation of another
Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html for
more information.
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure Homebrew parent directory has correct permissions (MacOS >= 10.13).] ***************************************************
skipping: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure Homebrew parent directory has correct permissions (MacOS < 10.13).] ****************************************************
skipping: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure Homebrew directory exists.] ********************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure Homebrew is installed.] ************************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure proper permissions and ownership on homebrew_brew_bin_path dirs.] ******************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure proper ownership on homebrew_install_path subdirs.] ********************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Check if homebrew binary is already in place.] ********************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Symlink brew to homebrew_brew_bin_path.] **************************************************************************************
skipping: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure proper homebrew folders are in place.] *********************************************************************************
ok: [localhost] => (item=Cellar)
ok: [localhost] => (item=Homebrew)
ok: [localhost] => (item=Frameworks)
ok: [localhost] => (item=Caskroom)
ok: [localhost] => (item=bin)
ok: [localhost] => (item=etc)
ok: [localhost] => (item=include)
ok: [localhost] => (item=lib)
ok: [localhost] => (item=opt)
ok: [localhost] => (item=sbin)
ok: [localhost] => (item=share)
ok: [localhost] => (item=share/zsh)
ok: [localhost] => (item=share/zsh/site-functions)
ok: [localhost] => (item=var)
TASK [geerlingguy.mac.homebrew : Force update brew after installation.] ****************************************************************************************
skipping: [localhost]
TASK [geerlingguy.mac.homebrew : Where is the cache?] **********************************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Ensure configured taps are tapped.] *******************************************************************************************
ok: [localhost] => (item=homebrew/core)
TASK [geerlingguy.mac.homebrew : Ensure blacklisted cask applications are not installed.] **********************************************************************
ok: [localhost] => (item=alfred)
TASK [geerlingguy.mac.homebrew : Install configured cask applications.] ****************************************************************************************
ok: [localhost] => (item=1password)
TASK [geerlingguy.mac.homebrew : Ensure blacklisted homebrew packages are not installed.] **********************************************************************
ok: [localhost] => (item=autoconf)
TASK [geerlingguy.mac.homebrew : Ensure configured homebrew packages are installed.] ***************************************************************************
ok: [localhost] => (item=awscli)
TASK [geerlingguy.mac.homebrew : Upgrade all homebrew packages (if configured).] *******************************************************************************
skipping: [localhost]
TASK [geerlingguy.mac.homebrew : Check for Brewfile.] **********************************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.homebrew : Install from Brewfile.] *******************************************************************************************************
skipping: [localhost]
TASK [geerlingguy.mac.dock : Install dockutil.] ****************************************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.dock : Remove configured Dock items.] ****************************************************************************************************
TASK [geerlingguy.mac.dock : Ensure required dock items exist.] ************************************************************************************************
included: /Users/your_username/.ansible/collections/ansible_collections/geerlingguy/mac/roles/dock/tasks/dock-add.yml for localhost => (item={'name': 'Launchpad', 'path': '/Applications/Launchpad.app/', 'pos': 1})
TASK [geerlingguy.mac.dock : See if Dock item Launchpad exists.] ***********************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.dock : Ensure Dock item Launchpad exists.] ***********************************************************************************************
skipping: [localhost]
TASK [geerlingguy.mac.dock : Ensure dock items are in correct position.] ***************************************************************************************
included: /Users/your_username/.ansible/collections/ansible_collections/geerlingguy/mac/roles/dock/tasks/dock-position.yml for localhost => (item={'name': 'Launchpad', 'path': '/Applications/Launchpad.app/', 'pos': 1})
TASK [geerlingguy.mac.dock : Check the current Dock position of Launchpad.] ************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.dock : Get current dock item position from output.] **************************************************************************************
ok: [localhost]
TASK [geerlingguy.mac.dock : Move dock item to the correct position.] ******************************************************************************************
skipping: [localhost]
PLAY RECAP *****************************************************************************************************************************************************
localhost : ok=21 changed=0 unreachable=0 failed=0 skipped=9 rescued=0 ignored=0
Tips
私が利用した時点で、以下のRoleの実行元コマンドでエラーがあったので共有です。
Role | 不具合 |
---|---|
geerlingguy.mac.mas | MasでのUninstallが動作しない ・mas-cli/mas#313 |
geerlingguy.mac.dock | homebrewでインストールしたdockutilが動作しないため、 別途最新のdockutilをインストールする ・kcrawford/dockutil#127 |
まとめ
今回geerlingguy.macを使用したMacのセットアップ方法をご紹介しました。こちらのRoleを利用することでAnsibleに詳しくなくても簡単にMac構築を自動化をできると思います。
また、こちらのRoleを使うだけでもだいぶ構築を自動化ができますが、Ansibleが提供している他のCollectionsを利用することでシステム設定ファイルなどの細かい管理もできますの興味の湧いた方はぜひAnsibleのドキュメントをのぞいてみてください。
参考までに、今回私が構築に利用したPlaybookをGitHubにあげておきます。
以上、たかやまでした!