背景
数年前からずっとMac Bookが欲しいと考えていました。
Apple Storeを覗いてスペックを見たりしながら夢を膨らませていました。
つい先日、満を持して、Mac Book Air M1を購入しました。
新しいPCを購入したあとにやることといえば...
そう、環境構築です。
自分専用の使いやすい環境を構築する。
とても楽しいワクワクする作業です。
手作業でポチポチインストールするのも楽しいので環境構築は苦ではなく、むしろ大好きです。
でもそれではこれまでと何も変わりません。
せっかくなので、これまでの仕事で経験してきたIaCの技術を使ってアプリケーションの自動インストールを行ってみようと考えました。
幸い、まだMac Book Air M1が届くまで時間があるようです。
ならばこの到着までの時間を使って、調査やAnsibleの準備を進めてみようと思います。
参考
AnsibleでMacの環境構築をしてみた
community.general.mas – Manage Mac App Store applications with mas-cli
チェックモード (「ドライラン」)
いつの間にかbrew caskが使用できなくなっていた話
(番外編)Macとの出会い
就職してからほとんどWindowsに触れていました。
クライアントもサーバも。
職場のPCはともかく、自宅のPCもメーカーPC、自作PC、ショップPCと渡り歩いてきました。
次第にスペック不足に陥ったり、PCが不調になったりと、パーツ交換を繰り返しながら使っていましたが、どうにも手間がかかるなという思いから、買い替えを決意。
どうせプライベートだし、Windowsに固執する必要はない、40歳のときに思い切ってMac(Mac mini Late 2012)に切り替えました。
購入直後からいきなり分解しHDDをSSDに換装、メモリも8GBから16GBに増設したりと、これまでの自作PCの経験を活かしカスタマイズ。
そこからはMacに慣れることや、MacでWindowsを動かす方法を調べたりと、楽しいPCライフが始まり、今に至ります。
調査してわかったこと
自動構築はAnsibleを使うようです。
Ansibleでアプリケーションをインストールするのは数多くの先人たちが情報を蓄積してくださっています。
調べたところ、Macはbrewコマンド、brew-caskコマンド、そして、masコマンドを使うことでCLIでアプリケーションをインストールすることができるようです。
Ansibleからはこれらコマンドに対して、インストールしたいアプリケーション情報を引数で渡してあげると良いみたいです。
masコマンドでインストーするアプリケーションのIDとは?
例えばLINEですが、調べてみると、brewでもbrew-caskでもインストール出来ないようでmasコマンドでインストールするようです。
masコマンドにはアプリケーションのIDが必要です。
では、LINEのIDはどうやったらわかるのでしょうか?
答えは簡単でした。
MacのApp Storeで「LINE」を検索してもわからなかったのですが、
ブラウザで検索すれば、URLにIDが表示されていました。
どうやら「LINE」は「539883307」のようです。
なので、インストールするコマンドはこの様になるようです。
mas install 539883307
Ansibleを実行する前にやっておくこと
アプリケーションの自動インストールはAnsibleでできそうだということがわかりました。
でもその前に、準備することがあります。
アカウントの設定とかもですが、Ansibleを実行する環境は事前に構築しておく必要があります。
ターミナルを起動し、以下のコマンドを実行して環境を整えておきます。
(これも自動化できればよいのですが...)
- Command line tools for Xcode
$ xcode-select --install
- Homebrew
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- Homebrew-Cask
$ brew install cask
- mas-cli
$ brew install mas
- Ansible
$ brew install ansible
- Ansible Community(Ansibleでmas-cliを使用するために必要な追加モジュールのインストール)
$ ansible-galaxy collection install community.general
- downloading role 'collection', owned by
[WARNING]: - collection was NOT installed successfully: Content has no field named 'owner'
ERROR! - you can use --ignore-errors to skip failed roles and finish processing the list.
このエラーがどうやっても解消できませんでした...
Ansibleで「community.general.mas」を使用していたので必要だと思うのですが、どうやってもインストールできませんでした。
仕方がありませんので、こちらのモジュールは使用せず、Ansibleでは純粋に「mas-cli」を使用することにします。
インストールしたいアプリケーションとインストール方法の調査
今回はクライアント用途のMac Book Air M1へのインストールなのでアプリケーションもそんなにたくさんはありません。
とりあえずは以下のアプリケーションをインストールします。
それぞれのインストール方法も合わせてチェックしておきました。
アプリケーション | インストール方法 |
---|---|
Python | brew install python |
Docker | brew install docker brew cask install docker |
iTerm2 | brew cask install iterm2 |
Typora | brew cask install typora |
LINE | mas install 539883307 |
CleanArchiver | brew install cleanarchiver |
VLC | brew cask install vlc |
Google Chrome | brew cask install google-chrome |
TweetDeck | mas install 485812721 |
DUET | brew cask install duet |
Ansible Playbookの作成
どうやらベストプラクティスなのか、以下のような構成を多く見ました。
私もこちらの構成に習って構築してみることにします。
構成
repositorys
└──/setup-mac
├── README.md
├── inventory
├── roles
│ ├── homebrew
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
│ ├── homebrew-cask
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
│ └── mas
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
└── site.yml
ドライラン
いきなりたくさんのアプリケーションをインストールするのもリスクなので、まずは各モードで一つづつ確認。
確認は母艦のMac miniで実行します。
こちらには既に色々なアプリケーションをインストール済みなので、再インストールになるのが嫌なので、Ansibleのチェックモードで確認します。
Ansible Playbookのチェック「ドライラン」
$ ansible playbook -i inventory site.yml --check
homebrewは問題なし。
TASK [homebrew : homebrew install] *********************************************
changed: [xxx.xxx.xxx.xxx] => (item={u'state': u'present', u'name': u'cleanarchiver'})
PLAY RECAP *********************************************************************
xxx.xxx.xxx.xxx : ok=1 changed=1 unreachable=0 failed=0
homebrew-caskはエラー...
TASK [homebrew-cask : homebrew cask install] ***********************************
failed: [xxx.xxx.xxx.xxx] (item={u'state': u'present', u'name': u'typora'}) => {"failed": true, "item": {"name": "typora", "state": "present"}, "msg": "Error: Unknown command: cask"}
どうやらcaskの指定はオプション扱いになったようです。
なので、Ansibleのcommandで「brew install --cask」を実行する形に変更してエラーを回避しました。
$ ansible-playbook --check -i inventory site.yml
PLAY [mac setup] ***************************************************************
TASK [homebrew-cask : homebrew cask install] ***********************************
skipping: [xxx.xxx.xxx.xxx] => (item={u'state': u'present', u'name': u'typora'})
PLAY RECAP *********************************************************************
xxx.xxx.xxx.xxx : ok=0 changed=0 unreachable=0 failed=0
masは「mas-cli」を使用することにしたのでエラーなく実行できたようです。
前述のように、本来は「community.general.mas」を使用したかったところですが...
残念ですが今回はこれで良しとします。
$ ansible-playbook --check -i inventory site.yml
PLAY [mac setup] ***************************************************************
TASK [mas : mas install] *******************************************************
skipping: [192.168.3.3] => (item={u'485812721 state': u'present', u'id': None})
PLAY RECAP *********************************************************************
192.168.3.3 : ok=0 changed=0 unreachable=0 failed=0
結果、各ファイルは以下のようになりました。
/homebrew/tasks/main.yml
---
# file: ~/setup-mac/roles/homebrew/tasks/main.yml
- block:
- name: homebrew tap
homebrew_tap:
name: "{{ item }}"
state: present
with_items: "{{ taps }}"
- name: homebrew install
homebrew:
name: "{{ item.name }}"
state: "{{ item.state }}"
with_items: "{{ packages }}"
tags:
- homebrew
/homebrew/vars/main.yml
---
# file: ~/setup-mac/roles/homebrew/vars/main.yml
taps:
- homebrew/cask
- homebrew/cask-versions
- homebrew/cask-fonts
- homebrew/core
packages:
- { name: python, state: present }
# - { name: cleanarchiver, state: present }
# - { name: docker, state: present }
/homebrew-cask/tasks/main.yml
---
# file: ~/setup-mac/roles/homebrew_cask/tasks/main.yml
- block:
- name: homebrew cask install
command: brew install --cask "{{ item.name }}"
with_items: "{{ packages }}"
tags:
- homebrew_cask
/homebrew-cask/vars/main.yml
---
# file: ~/setup-mac/roles/homebrew_cask/vars/main.yml
packages:
# - { name: docker, state: present }
- { name: iterm2, state: present }
- { name: typora, state: present }
- { name: vlc, state: present }
- { name: google-chrome, state: present }
- { name: duet, state: present }
- { name: google-japanese-ime, state: present }
- { name: cleanarchiver, state: present }
/mas/tasks/main.yml
---
# file: ~/setup-mac/roles/mas/tasks/main.yml
- block:
- name: mas install
command: mas install "{{ item.id }}"
with_items: "{{ packages }}"
tags:
- mas
/mas/vars/main.yml
---
# file: ~/setup-mac/roles/homebrew/vars/main.yml
packages:
- { id: ,539883307 state: present } # LINE
- { id: ,485812721 state: present } # TweetDeck
- { id: ,600925318 state: present } # Parallels Client
リモートリポジトリへ登録
今回はリポジトリは使用しませんが、資材の保管先として有志との活動で構築したgitlabを使用します。
予め、gitlab上にリポジトリを作成しておき、空のリポジトリをローカルにcloneし、資材をリモートリポジトリにpushしておきます。
実はこの活動を有志に相談したときに、次のテーマの構想が出てきたため、そのための事前準備として登録しておこうという魂胆です。
$ git clone http://xxx.xxx.xxx.xxx/example/setup-mac.git
$ cd setup-mac
$ git config --global user.name "example example"
$ git config --global user.email "example@example.com"
$ git add .
$ git commit -m "first commit"
$ git push
Username for 'http://xxx.xxx.xxx.xxx': example
Password for 'http://example@xxx.xxx.xxx.xxx':
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 469 bytes | 469.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To http://xxx.xxx.xxx.xxx/example/setup-mac.git
359cfc6..ca5b4de main -> main
Ansible Playbookの実行
$ ansible playbook -i inventory site.yml
無事にインストール完了!と言いたいところですが問題点が2つ。
cleanarchiverとdockerがインストールできませんでした。
terminalで直接実行してもだめです。
調べてみたところ、どうやらM1チップはちょっと癖があるようで、Intelチップと同じことが出来ないらしいです。
今回はDockerは手動でDocker Desktopをインストールしてコンテナを利用可能にしておきました。
そして、このあと、コンテナの利用でも問題が発覚することになります...
cleanarchiverは...今度調べてみます。
おわりに
今回の検証でMacへのアプリケーションのインストールはAnsibleで行えることがわかりました。
brewなのか、brew caskなのか、masなのか、masならIDを調べる、この段取りでなんとかなりそうだとわかりました。
もし、Mac Book Air M1の調子が悪くなり、再インストールすることになったとしても、このAnsible Playbookがあればすぐに同じ環境を構築することが出来ます。
さらに、アプリケーションを追加インストールしたければ、各vars/main.ymlに情報を追記してansible-playbookを再実行すればよいだけです。
Ansible Playbookは本来ならGitHubなどに登録しておき、必要に応じてgit cloneすればよいのですが、今回は完全に個人用だし、Ubuntu Serverにでも保存しておき、必要に応じて更新して再利用可能な状態にしておき、大事に保管しておきます。