Macに別れを告げて、クラウド中心の開発生活を始めるまで

昨年あたりから、Macやめたい病を患っていたのですが、2度の故障を経て、重たい腰を上げました。別にWindows使いたいわけもなく「ローカルが煩わしい」だけなので、**Windowsアプリは一切インストールしていません**。で、どうやって暮らしてるの? というお話です。

**TL;DR** このあたり↓を組み合わせていけば、クラウド生活可能:

- GCP (or AWS)
- Codeanywhere (or Koding or Cloud9)
- VPCネットワーク + VPN (IPsec+L2TP) + DNS
- Figmaほか、Webサービス各種

![Local and cloud-based dev (2).png](https://qiita-image-store.s3.amazonaws.com/0/1858/1ba0425a-89c5-5af0-f52a-96d79fc2cb60.png)

**追記**・この記事を書いていたら、AWS Cloud9が発表されました。選択肢が増えて何よりです。

## はじめに

本稿は、筆者が「**Mac断ち**」あるいは「**ローカルマシンから解脱**(げだつ)」する過程で見えてきた、ベスト(かも)プラクティス集に近いものです。

よく使うテキストエディタから、細かいMacアプリまで、どう代替していくか――ひとつひとつは大したことありませんが、全体としてはかなりのボリュームになります。これらを場当たり的に解決していくのはお勧めできません。本稿が、「解脱」全体像の把握と、スムーズな移行実施の参考になれば幸いです。

### 想定ユーザ

- テキストエディタ(Atomなど)を主体に作業するWeb開発者
- ターミナルでの作業をある程度こなす
- デザインはしない / あるいはWebデザインのみ

作業環境としては、Chromeだけあればいいので、OSは問いません。

- ChromeOS
- **Windows**
- **Android**
- Mac
- iOS (未検証)
- Linux

筆者の現在の環境はWindows/Androidがメインですが、他の環境でも基本OKです。(Pixelbook 2が欲しい)

**MEMO**: 本稿では、Xcodeが必要になるお仕事は想定していませんが、[ここ](https://xcloud.me/)とか[ここ](https://macminicolo.net/)とか、Macをクラウド化するソリューションもあります。やらないけど。

### アプリを入れない

環境構築の時間と手間を可能な限りゼロにしたいので、次の縛りを入れています。

1. Chrome以外のアプリを入れない (モバイルはその限りではない)
2. Chrome拡張もなるべく入れない


## テキストエディタ

Mac時代はAtomだったのですが、環境依存から脱却するべくWindowsへの切り替えのタイミングで一旦Kodingにしました。ただ、単純なテキストエディタとして見ると不満もあったので、現在はCodeanywhereをメインにしています。

オンラインで使える選択肢は、現状それほど多くありません。一時、レッドオーシャンになるかと思いきや、教育系のソリューションに鞍替えしたり、開発をストップしたり。本格的な開発環境を掲げて存続しているのは、以下の3つのほか[Eclipse Che](https://www.eclipse.org/che/)くらいでしょうか。

名称 | Good | Bad | 価格
:-- | :-- | :-- | :--
Codeanywhere | シンプルできれいなUI | プラグインなし | \$2/月～ (オススメは\$7)
Koding | 環境構築の自動化 | ちょっとバギー | $9.90/月～
AWS Cloud9 | AWSブランド | AWSブランド | $2/月程度～ ※

※AWS Cloud9について、特に追加の利用料は発生せず、仮想マシンの料金のみ。[AWSのページ](https://aws.amazon.com/cloud9/pricing/)に掲載されたモデルケースだと、t2.microで90時間稼働として$2ほど。(...いや、もっとかかると思う)

### Codeanywhere

[Codeanywhere](https://codeanywhere.com/)はAtomやSublimeTextに似たテキストエディタです。Atomを素のまま使っているのであれば、すんなり乗り換えられると思います。ただ、プラグイン的な拡張はできないので、AtomやSublimeをごりごりにカスタマイズしている人には向かないかも...。ある程度の妥協が必要になります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/e13ee35f-2b57-8d25-47e9-128bf10b3bdd.png)

- Web
- Android
- iPad (開発止まってる?)

の3つのプラットフォームで提供されています。Android版の更新は執筆時点の1週間前。活発に更新されているようです。Androidについては最後のセクションでも触れますが、PCでの作業をAndroidで続けられるのは非常に便利です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/8f8c7054-87aa-aa66-87a1-e711c668a9c7.png)


### Koding

いつの間にか、この分野の老舗の一角になっている[Koding](https://www.koding.com/)。方向性に紆余曲折があったものの、企業向けサービスを中心に据えたようです。フリーランス向けのプランも復活したので、[$9.90/月から](https://www.koding.com/pricing)使い始められます。見た目的にはエディタ + Slack。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/e1017f04-cfa2-cc8f-d273-4d6418ae65e7.png)

"Infrastructure as Code"の考え方を開発環境にも持ち込んでいるのが特徴です。([Terraform](https://www.terraform.io/)とかの流れ)

```yaml
google_compute_instance:
  google-instance:
   name: hoge
   machine_type: f1-micro
   disk:
    image: ubuntu-1404-lts
   zone: us-central1-a
```

上記のような設定を用意すると、それに従って作業環境をぽこっと作ってくれます。チーム内で環境を共通化したい場合や、案件別に環境をさくっと作りたい場合に便利です。

[GitHubにコードを公開](https://github.com/koding/koding)していて、利用者のコミットを受け付けているのは好感が持てます。一方で、エディタの開発が停滞しているのは残念です。外部エディタと連携する[kdコマンド](https://www.koding.com/docs/kd)の利用を推奨する方向に舵を切っているように見えます。Atomなど、好きなエディタで使えるのがありがたい一方、「解脱」とは逆方向です。

Dockerで環境を簡単に共通化できるようになった昨今、「作業環境の共通化」だけでは弱い気もしますが、コード上のコミュニケーションを売りに生き残るのか、どうなんだろう...?

### AWS Cloud9

先週発表の[AWS Cloud9](https://aws.amazon.com/cloud9/)ですが、Lambdaを扱うのが楽だったり、後述のDNS設定が不要だったり、AWSに統合されたことでいろいろ使いやすくなっている印象です。囲い込まれ感を気にしなければ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/3afdb88b-64e4-3851-6d68-f2429f0613c3.png)

あとは、他記事にゆずります。

- [【re:Invent 2017】AWS Cloud9を使ってみる 〜まずは起動まで〜](http://blog.serverworks.co.jp/tech/2017/12/01/reinvent_aws_cloud9/)
- [【速報】AWS Cloud9がリリースされました！ #reinvent](https://dev.classmethod.jp/cloud/aws/aws-reinvent-cloud9/)

### [参考] Atom + Nuclide

[Nuclide](https://nuclide.io/)はFacebookが開発するAtomのアドオンです。Nuclideを導入すると、デバッガほか各種機能が追加されIDEのようになります。その中で注目したいのは、リモート開発機能です。これを使うと、ファイルをローカルに置くことなくサーバ上に置いたまま、編集できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/412aac1f-39e0-215d-eb25-1dc4631bf7ed.png)

Nuclideの[リモート開発機能](https://nuclide.io/docs/features/remote/)を使うには、サーバ上で次のコマンドを実行し、Nuclide Serverを導入します。ファイアウォールで9090-9093のポートも開ける必要があります(設定で変更可能)。

```bash
$ npm install -g nuclide
```

### [参考] Atom + VPN + ネットワークドライブ

Nuclideというよりは素のAtomを使いたい場合、NFSやSMBでマウントしてしまう手があります。ただし、VPN(後述)を導入しているのが条件です。VPNを使わない場合は、SSHFSや[Mountain Duck](https://mountainduck.io/)も一応選択肢です (からめ手っぽいですが)。

プロトコル | Mac | Win | VPN? | 備考
:-- | :-- | :-- | :-- | :--
NFS | OK | 10 Pro以上 | 必要 | 
SMB | OK | OK | 必要 | サーバ側で要設定
WebDAV | OK | OK | できれば | サーバ側で要設定
SSH | 要クライアント | 要クライアント | 不要 | あまり一般的な方法ではない

WebDAVを外に晒すのは、セキュリティ面が心配なので、できればVPNの内側で運用したいところです。設定の簡便さからするとSMBな気もしますが、ファイル名の最大長問題は気にする必要がありそうです。(日本語ファイル名を使わなければ大丈夫かな...)

## ターミナル

Macの頃は標準の"Terminal"を使っていました。あとは[Hyper](https://hyper.is/)もいいですよね。ですが、これらはマシン依存を生んでしまいます。ここでは、ブラウザから使えるシェルたちを紹介します。参考まで、筆者について言えば、Codeanywhereのターミナルが多少多くて、SSH from the Browserがそれに続くくらいの利用頻度でしょうか。単に、導線としてエディタで作業中か、クラウドコンソールで作業中かによって手近な方を使っています。

名称 | Good | Bad
:-- | :-- | :--
SSH from the Browser (GCP) | ログイン不要 | 起動が遅い
Codeanywhere | エディタに統合 | 放置するとセッション切れ
Secure Shell | ローカルから使える | Chrome拡張が必要

**MEMO**: もし、EmacsやVim使いであれば、ローカル依存を受け入れて、ネイティブアプリのターミナルを入れたほうが無難かもしれません。逆に、そうでないならブラウザ上のシェルで十分です。

### SSH from the Browser

GCPにはブラウザ上で動作するターミナルが用意されています。[SSH from the Browser](https://cloud.google.com/compute/docs/ssh-in-browser)は、Compute Engineのインスタンス一覧から起動可能です。起動に1分ほど待たされるのが面倒ですが、パスワードや公開鍵の設定といったログインの手間がありません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/7f177baf-9e8d-5e23-f5a0-88375b0be32b.png)

他に見ない機能としては、「Upload file」機能が地味に便利です。ローカルからファイルを選択すると、ホームディレクトリに上げてくれます。

### Codeanywhere

Codeanywhereはエディタであると同時に、ターミナルでもあります。画面を切り替えず、エディタの横(や下)にターミナルを表示できます。以下は、接続方法で「SFTP - SSH」を選択している場合です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/7613c77d-3702-8fae-6ba8-d6a78ae8007a.png)


### Secure Shell (Chrome拡張)

[Secure Shell](https://chrome.google.com/webstore/detail/secure-shell/pnhechapfaindjhompbnflcldabbghjo?hl=en)は、Chrome拡張として実装されたターミナルです。ソースコードは[こちら](https://chromium.googlesource.com/apps/libapps/+/HEAD/nassh/)。ログイン画面がちょっと(ダサくて)ぎょっとしますが、いたって普通に使えます。ChromeOS環境ではデフォルト感があります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/2d429dee-e3d5-4a05-e583-b32a8b8b12c3.png)

あるいは、Chromeのアドレスバーで「ssh <kbd>TAB</kbd>」と入力して、接続先を指定することもできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/d2305d52-178a-63e7-ea61-31ece35dcb32.png)

### [参考] Hyper + Bash on Windows

クラウドにそもそも到達できない場合など、どうしても手元の環境からターミナルが使いたいケースが、ないとは言えません。MacやLinuxであれば、シェルがそのまま使えます。Windowsでもこの問題は解決しつつあります。

1. 管理者権限で開いたPowerShellから `Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux` を実行
2. Microsoft Storeから[Ubuntu](https://www.microsoft.com/en-us/store/p/ubuntu/9nblggh4msv6?SilentAuth=1&wa=wsignin1.0)をインストール
3. 実行

[詳しくはこちら](https://msdn.microsoft.com/en-us/commandline/wsl/install-win10)。Ubuntu以外にOpenSUSEも選べますよ!

Windowsのシェルは触りたくないので、[Hyper](https://hyper.is/)を入れて精神衛生を保ちます。Hyperの設定ファイルに次の1行を足して、bashを指定します。

```js
{
  ...
  shell: 'C:\\Windows\\System32\\bash.exe',
  ...
}
```


## 仮想マシン

作業環境をローカルマシンからクラウド上のVMに移行すると、マシン故障の心配から解放されます。欠点としては、ネット接続がないと一切の操作ができないことですが、最近は回線なしではそもそも仕事にならないので、あまり気にしていません。むしろ、移動中もAndroidでコードを書ける(見れる)のは、ちょっと新しい感覚です。回線が低速な地域に行く場合は、何か対策が必要ですが...

### Compute Engine

Googleの提供する仮想マシンです。AWSでいうところのEC2です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/b22eb5a1-13d1-b5f0-7cd1-b3e4fa1a31f1.png)

上図のように、Web上でポチポチ押して設定してもOKですが、作業環境を「再現可能」にするためにも、`gcloud`コマンドから生成するとその後が楽です。`gcloud`の[導入と初期設定についてはこちら](https://cloud.google.com/sdk/gcloud/)をどうぞ。

```bash
gcloud beta compute --project "${PROJECT_NAME}" \
  instances create "${INSTANCE_NAME}" \
  --zone "asia-northeast1-a" \
  --machine-type "g1-small" \
  --subnet "default" \
  --maintenance-policy "MIGRATE" \
  --service-account "${SERVICE_ACCOUNT}" \
  --scopes "https://www.googleapis.com/auth/cloud-platform" \
  --min-cpu-platform "Automatic" \
  --image "ubuntu-1604-xenial-v20171121a" \
  --image-project "ubuntu-os-cloud" \
  --boot-disk-size "10" \
  --boot-disk-type "pd-standard" \
  --boot-disk-device-name "${INSTANCE_NAME}" \
  --metadata-from-file startup-script="${TEMP}"
```

Macだと、お客さんごとにマシンを使い分けるわけにも行きませんが、仮想マシン(VM)ならいくらでも作れます。筆者のところでは、次のようなVMが10台ほど登録されていて、常時2,3台がONになっているという形に落ち着きました。ほんと、手元のMacに仮想環境立てるくらいだったら、GCP(やAWS)にインスタンス立てる方が楽ですね。

- **A**. オープンソースのライブラリ開発に使うVM。しょっちゅうつぶして作り直す
- **B**. VPN用に立ち上げっぱなしのVM
- **C**. 小規模案件のサポート用の共用VM。作業状態は残しておくけど、使う時だけ電源ON
- **D**. 大き目の案件は顧客やプロジェクトごとにVMを立てる。こちらも使う時だけ電源ON
- **E**. その他、気まぐれに立てる実験用VM

今のところ、これらのVMたちがひとつのVPCネットワークを形成しています。VPN(後述)を介して接続した手元のマシンからは、LAN内のサーバマシンのような感覚でアクセス可能です。チームの規模感によっては、VPCネットワークや、GCPプロジェクトの切り分けが必要になるかもしれません。

### Kubernetes Engine

すでにDocker化が進んでいるのであれば、作業環境についてもDocker化するのが自然な流れ。GCP上であればKubernetesクラスターを作っておいて、そこに必要なポッドを配置すれば良いだけです。

**MEMO**: [Android版のCloud Console](https://play.google.com/store/apps/details?id=com.google.android.apps.cloudconsole)がまだKubernetesの操作に対応していない(ON/OFFできない)ので、今のところ筆者はCompute Engineの方を主に使っています。

### AWS

GCPと基本同じことができます。割愛。

**MEMO**: AWSのUIデザインに日々のテンションがダダ下がりな人は、GCPに手を出してみるといいですよ。Material Designそのものの"Cloud Console"にほっとするはず。


## SSH接続と鍵管理

### Codeanywhere から GCP へ

Codeanywhereで、サーバへの接続時に"Public Key"を選択すると、Codeanywhere上で生成された鍵のペアを使うことができます。"GET YOUR PUBLIC KEY"のリンクをクリックすると公開鍵が表示されるので、これを接続先の環境に設定します。これだけで良いので、ひと手間減って楽です。秘密鍵を意識する必要もありません。(というか、Codeanywhereから秘密鍵を取り出す手段がそもそもありません)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/264fcdb2-4108-14a7-7d01-5ddd9a6ea484.png)

GCP側では、Compute Engine > Metadata のパネルで、プロジェクト全体で使用可能なSSH鍵を登録できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/82f3adb3-7dd2-47b3-f9e1-c04ce0b24ea0.png)

上図の`Edit`ボタンを押して、公開鍵を登録するのですが、鍵の書式については注意が必要です。(筆者は、ここでだいぶ時間を無駄にしました...)

よく見かける公開鍵は、

```
ssh-rsa AAAAB3NzaC1.....jM4udJC348IZ cognitom@macbook
```

というような形式を取っています。あるいは、最後をメールアドレスにしているひともいるでしょう。そもそも、この部分、何を書くのが正解なのでしょうか? 実は、公開鍵の書式としては、ここは**コメント欄だからなんでも良い**のです。

でも、GCPでのお作法としては、上記の公開鍵はうまく使えません。正しくは、

```
ssh-rsa AAAAB3NzaC1.....jM4udJC348IZ cognitom
```

のように`ssh-rsa [KEY_VALUE] [USERNAME]`のパターンでユーザ名を指定します。あるいは、`ssh-rsa [KEY_VALUE] google-ssh {"userName":"[USERNAME]","expireOn":"[EXPIRE_TIME]"}`のように、使用期限を設定することもできます。

まさか、SSHのコメント欄で設定するとは...! と仰け反ったのは私だけ? そういうものですか? 詳細については[こちらのドキュメント](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#sshkeyformat)をどうぞ。

### GCP から GitHub へ

GCP上の仮想マシンは、数十台にのぼるかもしれません。一台一台が、GitHubやGitLabほか公開鍵暗号を必要とするサービスにアクセスするとして、秘密鍵をどのように管理するかが問題です。

- 秘密鍵を数十回にわたって使いまわす
- VM作成時に自動生成する → 都度都度接続先に公開鍵を送る必要あり

どちらも、あまり望ましくなさそうですが、[Krypton](https://krypt.co/)がここで役に立ちます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/bacd94ef-5f51-fbdb-9af8-7f9474c88c3e.png)

キャッチコピーを見ると、

> A new home for your SSH private key

とありますね。"A new home"とはどこでしょうか? それはあなたのiPhoneやAndroidです。ブログ記事"[Introducing Kryptonite: the end of ~/.ssh/id_rsa](https://blog.krypt.co/the-end-of-id-rsa-d8fd2951d406)"を読むと、その意味がはっきりするのですが、秘密鍵をMacやサーバに置くのをやめようというのが趣旨です。代わりに、スマートフォンに秘密鍵を置いて、SSHで秘密鍵が必要なシーンが来たら、処理をスマートフォンに飛ばし、計算結果を(秘密鍵をではなく)返せば良いのです。

1. アプリをスマートフォンにインストール
2. CLIツールをインストール: `$ curl https://krypt.co/kr | sh`
3. ペアリング: `$ kr pair`
4. 通常通りsshを使う

ペアリングの方法が独特で、`kr pair`コマンドはQRコードをターミナルに表示します。これをスマートフォン側で読み取ると、完了です。それでは、実際にSSHを使ってみましょう。次のような流れになります。

- sshコマンドを実行 (あるいは、`git push`ほか、裏で`ssh`しているコマンド)
- スマートフォンに通知
- ユーザは、拒否 / 1回のみ承認 / 1時間承認 から選択
- 秘密鍵を使った計算結果を暗号化された通信経路で送信
- sshのハンドシェイク成功、通常のシーケンスに

### [参考] CodeanywhereからSakuraへ

さくらのレンタルサーバは、海外IPからのSSHアクセスを受け付けません。ただ、これはパスワード認証の場合で、公開鍵認証を使うのはOKです。Codeanywhereの公開鍵を`/home/ユーザ名/.ssh/authorized_key`に登録しておきます。なお、登録作業は、さくらのコントロールパネルのファイルブラウザ上から実施するのが楽です。

- [国外IPアドレスフィルタ](https://help.sakura.ad.jp/hc/ja/articles/206054272-%E5%9B%BD%E5%A4%96IP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF)


## VPN

VPN(Virtual Private Network)は、字句通り仮想のプライベートネットワークを作るための技術です。元々は、拠点間(本社と支社など)や、社外からのアクセスを暗号化する目的で使われていました。同様にクラウド上の仮想ネットワークに接続するにも使われます。

VPNがクラウド生活に必要な理由は、主に次の2つです。

- セキュリティ
- SSH以外のアプリケーションによる接続

開発中のマシンは、どうしてもセキュリティが甘くなります。これらをパブリックに晒すわけにはいきません。また、後者については、SSHトンネルを使う手もありますが、SSHトンネルを開くためのローカルアプリケーション(ないしChrome拡張)が必要になりますし、VMごとにトンネルを張るのは面倒すぎます。

VPNであれば、現在の主要なOS(モバイルを含む)に標準で含まれている機能なので、追加インストールが不要です。その点でも、VPNを使うほうが都合が良いのです。

技術 | ポート | OS標準 | 複数台への接続 | 備考
:-- | --: | :--: | :--: | :--
VPN | 500, 4500など | 標準 | 容易 | 導入が少し難しい
SSHトンネル | 22など | アプリ必須 | 難しい | SOCKSプロキシや、ポートマッピングなど面倒

### 導入

VPNはIPsecを使います。以前はモバイルで使うにはPPTPという頃もありましたが(10年前?)、IPsecはL2TPを組み合わせればモバイルにも対応できます。L2TPを使うかで方針を分けましょう。

- IPsec (拠点間のみ): GCP公式のCloud VPNが安心。迷わずこれで ※AWSにも同様のソリューションがあります
- IPsec + LSTP (モバイル対応): VPN用にVMを作成して、自前で構築

前者の場合は、事務所内でのみ作業をする想定です。固定IPも必要になります。

後者について、ひとりで使う分にはMicroインスタンスで十分のようです。もろもろの設定をすべて理解して行うにはそれなりの勉強がいるのですが、ただ使うだけであれば便利なスクリプトがあります。これを使いましょう。

- [IPsec VPN Server Auto Setup Scripts](https://github.com/hwdsl2/setup-ipsec-vpn)

VM上で自動実行する場合、標準出力を画面で確認できるとは限らないので、ファイルに書き出しています。

```bash
$ curl https://git.io/vpnsetup | sudo sh > vpn.log
```

もし、Androidでも利用するなら、設定で`sha2-truncbug`を`no`に書き換える必要があります。

```bash
$ curl https://git.io/vpnsetup | sed 's/sha2-truncbug=yes/sha2-truncbug=no/' | sudo sh > vpn.log
```

ただ、ややこしいのですが、旧いAndroidの場合は`yes`にする必要があります。ChromeOSでは別の設定の調整が必要であったりと、100%すべての環境に対応する設定は存在しません。各人の環境に合わせて多少の調整を覚悟しておきましょう。

**MEMO**: 上記、説明のため公開されているスクリプトをそのまま使っていますが、セキュリティに関わる部分なので、実際にはフォークした上で自分のリポジトリから読みだすようにするべきでしょう。

**MEMO**: GCPでVMを作成する際に、VPNサーバ用にするのであれば、IPフォワーディングをONにしておきます。`gcloud`コマンドからであれば、`--can-ip-forward`オプションをつけて作成します。

### プレビュー

従来のローカルマシンでの開発では、HTTPサーバを起動してブラウザから`localhost:8080`にアクセスしてすぐチェック、といったことが可能でした。クラウドのVM上のHTTPサーバにアクセスしようとすると、パブリックにHTTP(S)ポートを晒す必要がありますが、開発サーバとして望ましくありません。また、テストサイトにほかの認証を組み込むのも、間違いの元ですし、テスト環境としても確実に使いにくくなります。

一方、VPNを導入済みであれば、クラウド上であっても、LAN内の別サーバにアクセスするのと同じ使い勝手になります。以下のスクリーンショットは、お決まりのライブプレビューしているところ。URLが`localhost`ではなく、後述の作業用ドメインになっています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/7ac7e124-c2f5-360e-f4dd-0121050f14e0.png)


## DNS

VMの外向きのIPアドレスは起動のたびに変わりますが([Ephemeral](https://cloud.google.com/compute/docs/ip-addresses/#ephemeraladdress))、アクセスごとに接続先IPアドレスを変更するのは面倒です。IPアドレスを予約しておく手もありますが、作業環境の数だけ費用がかさむのはイマイチです。幸い、GCPやAWSのDNSはAPIから操作できます。起動時に自動的に設定してしまいましょう。

### ドメイン名を取得

すでに持っているものがあれば、そのサブドメインで十分です。せっかくなので新しいものを、という場合は最近増えたTLD(トップレベルドメイン)を選ぶのもあり。[Google Domains](https://domains.google.com/)で取得できるものだと、このあたり↓開発用に使い勝手(?)が良さそうです。

- .zone
- .team

### プライベートアドレス

GCPの場合、同じインスタンス名(=ホスト名)であれば、基本同じプライベートなIPアドレスが振られます。ただ、IPアドレスのままだと覚えにくいので、サブドメインを割り当ててしまいます。例:

- **instance-1**.hogehoge.team --> 10.146.0.1
- **instance-2**.hogehoge.team --> 10.146.0.2
- **instance-3**.hogehoge.team --> 10.146.0.3
- ...

これで、VPN越しにブラウザにプレビューする際、各段にアクセスしやすくなりました。

### パブリックアドレス

開発用の環境について、なるべくポートを晒すべきではありません。可能であれば、VPNだけにしたいのですが、そうするとCodeanywhereなどからアクセス出来なくなってしまうので、SSHのポートだけは開けておきます。その上で、例えば次のようなDNSのレコードを追加しておけば、SSHの設定が楽です。

- public.**instance-1**.hogehoge.team --> 35.200.101.20
- public.**instance-2**.hogehoge.team --> 35.200.151.30
- public.**instance-3**.hogehoge.team --> 35.200.201.40
- ...

筆者はプライベートアドレス用のホスト名に、`public.`の接頭辞をつけるルールで運用していますが、この辺は各人の自由です。チーム内で分かりやすいネーミングルールでどうぞ。

### APIから設定

`gcloud`コマンドからCloudDNSを操作するには、次のような手順を取ります。実際には、既存レコードの削除なども必要になりますが、雰囲気は伝わるでしょうか。

```bash
TEMP=$(mktemp -u)
gcloud dns record-sets transaction start -z "${ZONENAME}" --transaction-file="${TEMP}"
gcloud dns record-sets transaction add -z "${ZONENAME}" --transaction-file="${TEMP}" \
  --name "${HOSTNAME}.${ZONE}." --ttl 300 --type A "${PUBLIC_ADDRESS}"
gcloud dns record-sets transaction execute -z "${ZONENAME}" --transaction-file="${TEMP}"
```

## 構築の自動化

ここまでの話を、手動でやるのはナンセンスです。自動化します。
GCPを例に説明しますが、他のAWSでも同様のことは可能です。GCPの導入については触れません。公式ドキュメントを参照してください。

VMのイメージをゴリゴリに作ってしまうと、「秘伝のタレ」化させる自信があるので、素のディストリビューション(Ubuntu 16とか)から構成する方式にします。今のところ、ChefやAnsibleが必要になるほどは複雑になっていませんが、規模次第。

### Startup Scripts

Comupte Engineの場合、Startup Scriptsに書いておくと、パッケージのインストールや設定を自動化できます。Dockerであればdockerfileに書けば良い系のものですが...

もう少し、冪等性のある書き方ができそうですが、ここでは初回と2回目以降で処理を分けています。まだ改善の余地あり。

```bash
#!/bin/sh

ZONE=hogehoge.team
ZONENAME=hogehoge-team
USERNAME=cognitom

INITIALIZED_FLAG=".startup_script_initialized"

main()
{
  tell_my_ip_address_to_dns
  if test -e $INITIALIZED_FLAG
  then
    # Startup Scripts
    update
  else
    # Only first time
    setup
    touch $INITIALIZED_FLAG
  fi
}

# Installation and settings
setup()
{
  # Foundamental tools
  apt-get update
  apt-get install -y build-essential
  apt-get install -y chromium-browser

  # Krypton CLI for key management
  curl https://krypt.co/kr | sh

  ...略

  # Git
  sudo -i -u "${USERNAME}" git config --global user.name "Tsutomu Kawamura"
  sudo -i -u "${USERNAME}" git config --global user.email "cognitom@gmail.com"
}

# Update on each startup except the first time
update()
{
  apt-get update
  apt-get upgrade
  kr upgrade
}

tell_my_ip_address_to_dns()
{
  ...略
}

main
```

こういったstartup scriptsを必要に応じて用意しておけば、再現性のある環境が作れます。インスタンスの作成画面から書き込めるようになっています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/5fe264be-1c03-9c52-2d0d-3f82dd55e203.png)

### Cloud Shell

VMの設定の自動化だけでなく、できればVMの作成自体を自動化したいので、`gcloud`コマンド主体にシェルスクリプトを組みます。

でも、お気づきでしょうか? 最初のVMを作るまで、シェルの実行環境がないような...? でも心配はありません。GCPにはVMを立てる前から使えるシェルとして「Cloud Shell」が用意されています。画面右上の「>_」アイコンをクリックすればすぐに使えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/d099c818-7070-4df6-dd0d-441fd5670ab4.png)

これで安心してShell Scriptを利用できます。次のようなコード(create.sh)を用意します。前節のStartup Scriptsが自分のGitHubリポジトリに置いてある想定です。`STARTUP_SCRIPT_URL`は実際のURLに書き換えてください。

```bash
#!/bin/sh

# Settings
PROJECT_NAME="personal-env"
STARTUP_SCRIPT_URL="https://raw.githubusercontent.com/path/to/startup-script.sh"


# Arguments
INSTANCE_NAME="$1"

if test "$INSTANCE_NAME" = ""
then
  echo "[Error] Instance name required." 1>&2
  exit 1
fi

# Download startup script
TEMP=$(mktemp -u)
curl "${STARTUP_SCRIPT_URL}" > "${TEMP}"

# Get Service Account information
SERVICE_ACCOUNT=$(\
  gcloud iam --project "${PROJECT_NAME}" \
    service-accounts list \
    --limit 1 \
    --format "value(email)")

# Create a instance
gcloud beta compute --project "${PROJECT_NAME}" \
  instances create "${INSTANCE_NAME}" \
  --zone "asia-northeast1-a" \
  --machine-type "g1-small" \
  --subnet "default" \
  --maintenance-policy "MIGRATE" \
  --service-account "${SERVICE_ACCOUNT}" \
  --scopes "https://www.googleapis.com/auth/cloud-platform" \
  --min-cpu-platform "Automatic" \
  --image "ubuntu-1604-xenial-v20171121a" \
  --image-project "ubuntu-os-cloud" \
  --boot-disk-size "10" \
  --boot-disk-type "pd-standard" \
  --boot-disk-device-name "${INSTANCE_NAME}" \
  --metadata-from-file startup-script="${TEMP}"
  
rm "${TEMP}"
```

実行は、`sh create.sh hello`といった感じでスクリプトを呼び出します。`hello`の部分はインスタンス名(ホスト名)を指定しています。好きなものを指定します。


## モバイルで使う

ソフトウェア開発にMacやPCは必須でしょうか? 「クリエーターには必要だ。タブレットは消費にしか向かない」という人もいれば、もうiPadでしか使わないビジネスマンもいます。プログラマは「コンピュータが大好きな人種」な分、ある意味ではモバイルからもっとも遠いのかもしれません。

一方で、サーバにログイン出来さえすれば仕事できるのも確かです。その意味では、もっともモバイル向きのはずなんだけど...? 別にiPadにHappy Hackingを繋いではいけない法はないのです。

- [The iPad Pro as main computer for programming](https://jann.is/ipad-pro-for-programming/)

次のスクリーンショットは、Android端末からVPN接続して(左)、ライブプレビューしながらHTMLを書いてみたところ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1858/6b4fb210-5f41-69c4-e552-ccaf7c47e02e.png)

VPNはOS標準の機能なので、とりあえずこの2つのアプリがあれば始められます。

- [Codeanywhere](https://play.google.com/store/apps/details?id=com.codeanywhere.mobile)
- [Cloud Console](https://play.google.com/store/apps/details?id=com.google.android.apps.cloudconsole)


## アプリケーション

開発中心であっても、他のツールも必要です。ほとんど機能的には「Webでいいじゃん」なのは気が付きつつ、職場のAdobe依存度、Office依存度による、という感じでしょうか。3DやUnity、動画編集はデスクトップにせざるを得ないですが、デスクトップ依存な分野は限定されてきた感があります。

**MEMO**: 一点、注意がいるとすると、Figmaなど先進的なサービスも「タッチパネル対応」はあまりしていません。そのためiPadで本格利用できるかというとNGです。現時点では、ほとんどのサービスで、次のような使い分けになるでしょう。

- **ノートPC**: ブラウザ版ですべての操作が可能、ただしトラックパッド(マウス)操作が前提
- **タブレット**: ブラウザ版はビューワのみ、専用アプリがあれば編集も
- **スマートフォン**: 同上

### Webサービス

Gmail (Inbox), Google Calendar, Facebook, Help Scout, Squareほか、業務で使うもののほとんどはもはやWeb中心。[Skype](https://web.skype.com/)ですら、今はWeb対応です。書き出すと切りがないので、いくつか使用頻度の高いものだけピックアップ。

#### デザイン

**Adobe断ち**ができるか次第ですが、すでにSketchに移行済みであればFigmaに移るのは簡単です。印刷系も日本語無視できれば、選択肢が出てきています。

- [Figma](https://www.figma.com/) - Sketch代替、Web系は基本これひとつで
- [Gravit Designer](https://www.designer.io/) - 印刷系も対応、ただし日本語フォントNG
- [Polarr](https://polarr.co) - 画像編集
- Google Photo - 写真管理と簡単な調整

そのほか、プロトタイプ系はむしろWeb版ありきが多いので割愛。逆に弱いのはPhotoshopやお絵描き方面ですが、この辺は最近タブレットのアプリが台頭しているので、必ずしもデスクトップでやらなくても、と。(追記: 筆者の使い方だと、Polarrが必要十分)

#### オフィス

- Google Docs
- Google Sheet
- Google Slide
- Dropbox Paper
- [Freee](https://www.freee.co.jp/) - 弥生会計もWeb版あり

定番ですね。Microsoft OfficeのWeb版の完成度はその後上がっているのかな?

### Chrome拡張

それほどは必要にならないです。Chrome拡張に頼ってしまうと、別のブラウザに移行しにくくなるので、ここもなるべくなら排していきたい部分。

- [Secure Shell](https://chrome.google.com/webstore/detail/secure-shell/pnhechapfaindjhompbnflcldabbghjo?hl=en) - ターミナルのところで前述
- [VNC® Viewer for Google Chrome™](https://chrome.google.com/webstore/detail/vnc%C2%AE-viewer-for-google-ch/iabmpiboiopbgfabjmgeedhcmjenhbla)

### サーバにインストールするもの

個人用の作業環境サーバにインストールする想定のアプリケーションです。個人的には、今後この分野を期待しています。Electronベースのアプリケーションをサーバ用に「逆輸入」できると良いのですが... (今の時点ではそのようなソリューションはなし)

- [adminMongo](https://adminmongo.markmoffat.com/)
- [phpMyAdmin](https://www.phpmyadmin.net/) - 意外に代替がない... ><
- [git-webui](https://github.com/alberthier/git-webui)

※ここは後日たぶん書き足します。


## まとめ

### で、結局いくらなの?

周辺サービスはさておき、エディタ回りの環境でいくらかかるかを計算してみます。標準的と思われるケースで、作業用(small)とVPN用(micro)の2台を常時稼働で、他環境(1 vCPU)は100時間くらいの稼働という仮定で:

サービス | 価格 | $1=&yen;110換算
:-- | --: | --:
Compute Engine | $20 | &yen;2,200
Codeanywhere | $7 | &yen;770
**合計** | $27 | **&yen;2,970**

実際には、ドメイン更新料や、GitHub、1Password、TestingBotほかあるんですが、この辺はMac時代にも払っているので割愛します。ちなみにKryptonの利用は無料です。

年額換算で3.6万円程度の出費になるわけですが、これを高いと見るか、安いと見るか。Chromebookなどの廉価な端末で済むなら大したことはない、と考えることもできるでしょう。筆者としては、Macが故障しても「**その1分後から別マシンで開発が続けられる**」なら、この程度出しても全然いいかなと。

### マシン故障は怖くない

緊急時は、スマートフォンからSSHで対応、というのは今でも時折見かける光景ですが、大抵は本番環境やテスト環境へログインしての作業になってしまいます。これでも応急処置くらいはできるかもしれませんが、それを超えた作業になると「作業環境がない」ことが致命的になります。

お気に入りだったMacBook(Retina)は発売直後の2015年夏に購入した後、2016年の12月、2017年の9月と故障に見舞われました。どちらのケースもマザーボードを含むキーボード側の全面交換だったので10万近い修理金額。Apple Careに入っていれば、多少抑えられるし、金額自体は仕方がないと思うんです。でも、移行作業と時間がつらい。代替機のセットアップに半日、と思ったけどテンション低めなので全日。1週間から10日ほどで工場からMacが帰ってくると、アップルストアにお迎えに出かけて、また移行作業で1日つぶれる。ジーニアスバーの予約も最近はすぐ取れません。

「もう、ローカルマシンに振り回されたくない」
「もう、次買うのはMacじゃないかもしれない」

でも、こんな思いは過去のものです。もうぜんぶ雲の上(クラウド)だし。