【PCバックアップ対策】Ansibleを使ったMacの初期セットアップの自動化

## はじめに
この記事は主にMacを使用している方で、自分と同じように面倒臭がりな人を想定として書いています。
また、SESなどを行なってる方で、現場が変わる度にMacをセットアップするのも面倒臭くなってきたという方にも役に立つと思います。

### 何をやろうとしているのか

`Ansible`と呼ばれるサーバー構成管理ツールを使用して、Macのセットアップを自動化しちゃおうぜいって感じです。面倒毎は全部自動化しようというのが弊社の理念でもあります。（え？）
今回はあくまで簡易的な自動化として、自分がMacに入れているアプリケーションやその他の設定のインストールを`Ansible`に代行してもらいます。

## Ansibleを使うためにインストールと必要なファイルとか

#### Ansibleのインストール

brewでも出来るのですが、brewのインストールはAnsibleに任せたいのでpythonでインストールしましょう。
pipなくて出来ひんわ！って人はbrewのインストールだけして`brew install ansible`でも大丈夫。

```bash
pip install ansible
```

#### Ansibleを動かすためのファイルとか

単純に動かすだけなら以下の3ファイルだけで動かすことが可能です。

* Inventory（どのサーバーを管理するのかのhostsファイル
* Ansible.cfg（Ansible全体の設定
* Playbook（サーバーをどのように管理するのかの設定ファイル ymlで書く

実行の仕方は以下のような感じ。

```bash
ansible-playbook -i ./hosts playbook.yml
```

#### 簡易的に使うAnsibleコマンド

- `ansible-playbook playbook.yml —syntax-check`
    - 構文エラーチェック
- `ansible-playbook playbook.yml —tasklist`
    - 実行するタスクを一覧で出す
- `ansible-playbook playbook.yml —check`
    - 実行したらどう結果を返すかのテスト

#### Ansibleを動かすための準備①：Inventory(host)を用意する
今回はlocalhost、つまり自分のPCなのでファイルの中身にはlocalhostと書くだけ

```hosts:hosts
localhost
```

#### Ansibleを動かすための準備②：Ansible.cfg(設定ファイル)を用意する

本来であれば、複数のサーバーなどを管理する関係上、鍵のpathとかをここにも書くのですが、設定するのは自分のPCだけなので、ここでは単純にhostsファイルのpath設定だけ行います。

```config:ansible.cfg
[defaults]
hostsfile = ./hosts
```

#### Ansibleを動かすための準備③：Playbook.yml(実行ファイル)を用意する

ここでは実際にどういったタスク（実行したい内容）を記載していきます。
記事内では、Macのセットアップ自動化と言っていますがMacで普段自分が使用しているアプリケーションとパッケージのインストールを行います。

```yml:playbook.yml
  
---
- name: set up my mac
  hosts: localhost
  connection: local
  vars:
    brew_pkgs:
      - tree
      - wget
      - bat
      - fd
      - ripgrep
      - starship
      - exa
    brew_cask_apps:
      - vagrant
      - virtualbox
      - docker
      - sublime-text
      - visual-studio-code
      - firefox
      - karabiner
      - shiftit
      - slack
      - skitch
      - kindle
      - postman
      - cheatsheet
      - macwinzipper
      - clipy
      - sequel-pro
      - alfred
      
  tasks:
    - name: Install First Homebrew
      shell: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

    - name: Update homebrew itself first
      homebrew: update_homebrew=yes

    - name: Install brew pkg 
      homebrew: name {{ item }}
      with_items: "{{ brew_pkgs }}"

    - name: Install application
      homebrew_cask:
        name: "{{ item }}"
        state: "present"
        install_options: "appdir=/Applications"
        accept_external_apps: yes
      with_items: "{{ brew_cask_apps }}"
```

- **task1:** `Install First Homebrew`
    - Homebrewがないと話にならないのでまずはこれだけ最初にインストールします
- **task2:** `Update homebrew itself first`
    - Homebrewのupdateを行います。（念のために
- **task3:** `Install brew pkg `
    - 必要なパッケージをインストール
- **task4:** `Install application`
    - アプリケーション類をインストール

やってることはHomebrewとbrewcaskで必要なものをインストールしているだけです。
これを応用すると、Macの詳細設定（例えばFinderで隠しファイルを表示するとか、トラックパッドの設定なども）Ansibleで自動化可能です。

上記を実行すると、ymlで書かれてる`task`が実行されます。
Ansibleの良いところは、存在チェックを行なってくれるので、すでにインストール済みのアプリケーションやパッケージがあった場合はスキップしてくれます。

上記を実行すると以下のような感じ

```bash
TASK [Install brew pkg] ***********************************************************************************************************************************************
ok: [localhost] => (item=tree)
ok: [localhost] => (item=wget)
ok: [localhost] => (item=bat)
ok: [localhost] => (item=fd)
ok: [localhost] => (item=ripgrep)
ok: [localhost] => (item=starship)
ok: [localhost] => (item=exa)

TASK [Install application] ******************************************************************************************************************************************
ok: [localhost] => (item=vagrant)
ok: [localhost] => (item=virtualbox)
ok: [localhost] => (item=docker)
ok: [localhost] => (item=sublime-text)
ok: [localhost] => (item=visual-studio-code)
ok: [localhost] => (item=firefox)
failed: [localhost] (item=karabiner) => {"ansible_loop_var": "item", "changed": false, "item": "karabiner", "msg": "Error: Cask 'karabiner' is unavailable: No Cask with this name exists. Did you mean one of these?\nkarabiner-elements\nkarabiner-elements"}
ok: [localhost] => (item=shiftit)
ok: [localhost] => (item=slack)
ok: [localhost] => (item=skitch)
ok: [localhost] => (item=kindle)
ok: [localhost] => (item=postman)
ok: [localhost] => (item=cheatsheet)
ok: [localhost] => (item=macwinzipper)
ok: [localhost] => (item=clipy)
ok: [localhost] => (item=sequel-pro)
ok: [localhost] => (item=alfred)

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

成功だったらok, 失敗してたらしたでfailで出力されて終了します。便利！
これで「俺自宅のPCに入れていた、あのアプリなんやったけ〜」ってことが無くなります。
上記をGitHubに上げておいて実行すれば、自宅のPCと変わらない環境が揃います。

#### 補足

pythonのversion問題で以下のような警告が出る場合があります。

```bash
TASK [Gathering Facts] ************************************************************************************************************************************************
[WARNING]: Platform darwin on host localhost is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter
could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
ok: [localhost]
```

その場合は`ansible.cfg`にpythonのpathを記載すればOK。
pythonのpathは適宜環境によって変えてください。

```conf:ansible.cfg
[defaults]
interpreter_python = /usr/bin/python3
```

#### 余談1：Ansible分からない人向け

自分も全然詳しくないので『基本のキ』はドットインストールの講座で勉強しました。
サポートも終わっていますが、概念や簡易的な構築の参考にはなるので、全く分からない人は動画の流し見だけでもおすすめ。
https://dotinstall.com/lessons/basic_ansible

#### 余談2：自分がやっているMac設定

`dotfile`と呼ばれるものたちをGitHubに上げてしまいます。
自分で設定してるエイリアスとかの方を覚えてしまっていて、正規のコマンドとか忘れているのでPCが変わった時に「あれ？あのコマンドってなんやったけ？」ってことがないようにしています。

- .zshrc
- .bashrc
- .bash_profiles
- .profiles

その後、シンボリックリンクをホームディレクトリに張る。
`ln -s ./repository_name０/dotfiles/.bash_profile ~/`
シンボリックリンクを貼っておくと、もし自分がローカルで変更した場合でもgitのdiffが取れるかつ、それをcommitして他のPCでpullすれば共有することが簡単です。

#### 余談3: VSCodeの拡張機能もGitHubに上げておきたい

エディターの設定とかもエクスポートして、一気にインストールしたい場合とかも結構多いと思います。
VSCodeは`code --list-extensions | xargs -L 1 echo code --install-extension`でexportしておけばinstallコマンドで代替しておけるので、これ自体をGitHubに上げておけばPC変わっても大丈夫。

```bash
❯ code --list-extensions | xargs -L 1 echo code --install-extension
code --install-extension abusaidm.html-snippets
code --install-extension bmewburn.vscode-intelephense-client
code --install-extension CoenraadS.bracket-pair-colorizer
code --install-extension cstrap.flask-snippets
code --install-extension cweijan.vscode-mysql-manager
code --install-extension EditorConfig.EditorConfig
code --install-extension felixfbecker.php-debug
code --install-extension felixfbecker.php-intellisense
code --install-extension formulahendry.docker-explorer
code --install-extension hangxingliu.vscode-nginx-conf-hint
code --install-extension HookyQR.beautify
code --install-extension jakebathman.mysql-syntax
code --install-extension kevinkyang.auto-comment-blocks
code --install-extension mikestead.dotenv
code --install-extension mohsen1.prettify-json
code --install-extension ms-azuretools.vscode-docker
code --install-extension MS-CEINTL.vscode-language-pack-ja
code --install-extension ms-python.python
code --install-extension ms-vsliveshare.vsliveshare
code --install-extension nmrmsys.vscode-sql-formatter-mod
code --install-extension onecentlin.laravel-blade
code --install-extension onecentlin.laravel5-snippets
code --install-extension quicktype.quicktype
code --install-extension Shan.code-settings-sync
code --install-extension tht13.python
code --install-extension Umoxfo.vscode-w3cvalidation
code --install-extension vscode-icons-team.vscode-icons
code --install-extension xabikos.JavaScriptSnippets
code --install-extension yongzeyao.dom-code-snippets
```

終わり。