Open10

M1 (Apple Silicon) Mac セットアップログ

MacBook Air (13 inch, M1)を買ったので、(主に自分のために)セットアップログを書く。

以下をインストール:

  • Google Chrome (ダウンロード画面でIntel版とARM版どちらにするか聞かれるのでARMを選択)
  • Alfred
  • Contexts
    • Sidebar: No display
    • Search: Search withを無効化
  • Moom
  • Alacritty
  • Visual Studio Code
  • Karabiner-Elements (v13.1.0)
  • Tailscale
  • JetBrains Mono https://www.jetbrains.com/ja-jp/lp/mono/

Chrome以外はamd64なのでRosetta 2で動いてる。

  • メニューバーを隠す
    • System Preference -> Dock & Menu Bar -> Automatically hide and show the menu bar
    • (これ、前バージョンはGeneralにあった気がする)
  • (USキーボードの)Caps LockをControlにする
    • System Preference -> Keyboard -> Modifier Keys...
  • Smart quotes, dashesを無効化
    • System Preference -> Keyboard -> Text -> Use smart quotes and dashesを外す
  • キーリピートを速くする
    • defaults write -g InitialKeyRepeat -int 10
    • defaults write -g KeyRepeat -int 1
  • SSH鍵作る
    • ssh-keygen -t ed25519
    • GitHubに公開鍵を登録しとく
  • Karabiner-Elements
    • Simple modifications
      • caps_lock -> left_control
    • Complex modifications
      • 「コマンドキーを単体で押したときに、英数・かなキーを送信する。(左コマンドキーは英数、右コマンドキーはかな) (rev 3)」を追加
      • 「Quit application by pressing command-q twice」

Homebrewをいれる。Alacrittyで

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

するだけ(Rosetta 2が使われる)

Terminal.appで同じようにインストールすると

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
Homebrew is not (yet) supported on ARM processors!
Rerun the Homebrew installer under Rosetta 2.
If you really know what you are doing and are prepared for a very broken experience you can use another installation option for installing on ARM:
  https://docs.brew.sh/Installation

と言われるが、これはTerminal.appはARMバイナリで動いているため。Terminal.appのGet InfoからOpen with Rosettaにチェックを入れれば、Intelバイナリ + Rosettaで動くので、Homebrewも入れられるはず。

ARMバイナリを入れたいなら、現時点ではMacPortsかな。

HomebrewでGoを入れてみる。問題なさそう。

$ brew install golang
$ go version
go version go1.15.5 darwin/amd64
$ cat main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello world")
}
$ go build -o out .
$ file out
out: Mach-O 64-bit executable x86_64
$ ./out
Hello world

その他Homebrewでいれたもの:

brew install starship

ARM MacではまだDockerが使えないので、適当なLinuxマシンのDockerデーモンをMacBookからつかう。一応、TLSでクライアント認証しておく。
だいたい Protect the Docker daemon socket | Docker Documentation の通り。サーバ、クライアント両方にTailscaleをインストールしてあるので、外出先でもWireGuard越しでDockerがつかえるはず。

サーバ(dockerdが動いているマシン)で

# mkdir /etc/docker-tls
# cd /etc/docker-tls
# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
..................................................................++++
..........................++++
e is 65537 (0x010001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:
# openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:yourhost.example.com
Email Address []:
# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
...........................................++++
...................................................................................................++++
e is 65537 (0x010001)
# openssl req -subj "/CN=yourhost.example.com" -sha256 -new -key server-key.pem -out server.csr
# echo subjectAltName = DNS: yourhost.example.com,IP:192.168.0.x,IP:100.x.y.z >> extfile.cnf
# echo extendedKeyUsage = serverAuth >> extfile.cnf

100.x.y.zはTailscaleのアドレス。

# openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=CN = yourhost.example.com
Getting CA Private Key
Enter pass phrase for ca-key.pem:

クライアント(Mac)で

$ mkdir ~/.docker
$ cd ~/.docker
$ openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
...........................................................................................................................................................................................................++
.......................................................................................++
e is 65537 (0x10001)
$ chmod 400 key.pem
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr

cllient.csrをサーバの/etc/docker-tls/client.csrにコピーしておく。

サーバ(dockerdが動いているマシン)で

# echo extendedKeyUsage = clientAuth > extfile-client.cnf
# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out mba-client-cert.pem -extfile extfile-client.cnf
Signature ok
subject=CN = client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
# rm -v client.csr server.csr extfile.cnf extfile-client.cnf
# chmod -v 0400 ca-key.pem key.pem server-key.pem
mode of 'ca-key.pem' changed from 0600 (rw-------) to 0400 (r--------)
mode of 'key.pem' changed from 0600 (rw-------) to 0400 (r--------)
mode of 'server-key.pem' changed from 0600 (rw-------) to 0400 (r--------)
# chmod -v 0444 ca.pem server-cert.pem mba-client-cert.pem
mode of 'ca.pem' changed from 0644 (rw-r--r--) to 0444 (r--r--r--)
mode of 'server-cert.pem' changed from 0644 (rw-r--r--) to 0444 (r--r--r--)
mode of 'cert.pem' changed from 0644 (rw-r--r--) to 0444 (r--r--r--)

mba-client-cert.pemをクライアントの~/.docker/cert.pemに、ca.pemをクライアントの~/.docker/ca.pemにコピーしておく。

/etc/docker/daemon.jsonに以下の内容を書いて、TLSを有効化。

{
	"tlsverify": true,
	"tlscacert": "/etc/docker-tls/ca.pem",
	"tlscert": "/etc/docker-tls/server-cert.pem",
	"tlskey": "/etc/docker-tls/server-key.pem"
}

systemctl edit docker.serviceでoverride.confを開いて、以下のようにTCPでも受け付けるようにする。

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376
# systemctl daemon-reload
# systemctl restart docker

クライアント(Mac)で

Dockerコマンド(クライアント)を入れる:

$ brew install docker
$ echo 'export DOCKER_HOST=tcp://100.x.y.z:2376' >> ~/.zshrc
$ echo 'export DOCKER_TLS_VERIFY=1' >> ~/.zshrc
$ source ~/.zshrc
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:e7c70bb24b462baa86c102610182e3efcb12a04854e8c582838d92970a09f323
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

Alacrittyを使ってしまうと、arm環境が使えないのでTerminal.appを使うようにする(現状Alacrittyがamd64のみ)。さらにtmuxをarmビルドに変えて、シェルやコマンド単位でarm64, amd64を切り替える運用をすることにする。

まず、tmuxをarmビルドにするために、(現状Homebrewがarm対応していないので)MacPortsを使ってtmuxを入れる。

https://www.macports.org/install.php

Terminal.appで

$ arch
arm64
$ sudo port install tmux
$ which tmux
/opt/local/bin/tmux
$ file /opt/local/bin/tmux
/opt/local/bin/tmux: Mach-O 64-bit executable arm64

tmuxを起動して、archを実行してみると、arm64になっていることが確認できる。

$ tmux
(in tmux)$ arch
arm64

zshrcに以下を追加:

alias brew='arch -x86_64 /usr/local/bin/brew'
alias x64='exec arch -x86_64 "$SHELL"'
alias a64='exec arch -arm64e "$SHELL"'

Homebrewはamd64で動かす必要があるので、エイリアスを貼っておく。こうすることでbrew installがarm64のシェルからでも実行できる。
x64はシェルをamd64に変えるエイリアス。

https://zenn.dev/ryotarai/scraps/488c14162e24adb59db4#comment-7cc5bfe7a51dbdb177b7 でDockerが使えるようになったので、kindを動かしてみる。

$ brew install kind
$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.19.1) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind! 😊
$ kubectl cluster-info --context kind-kind

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
The connection to the server 127.0.0.1:51270 was refused - did you specify the right host or port?

kindはDockerがローカルで動いていることを想定して、port bindingをしているので、雑にSSH port forwardingして解決する。

#!/usr/bin/env ruby
require 'json'
require 'shellwords'

ports = []

inspect_cmd = Shellwords.join(['docker', 'inspect'] + `docker ps -q`.each_line.map(&:strip).to_a)
containers = JSON.parse(`#{inspect_cmd}`)
containers.each do |container|
  port_bindings = container.dig('HostConfig', 'PortBindings')
  next if port_bindings.nil?
  port_bindings.each do |container_port, host_ports|
    host_ports.each do |host_port|
      ports << host_port["HostPort"].to_i
    end
  end
end

ssh_args = ['ssh', '-N', '-L']
ports.each do |port|
  ssh_args << "#{port}:127.0.0.1:#{port}"
end
ssh_args << ENV.fetch('FORWARD_DOCKER_PORTS_SSH_HOST')
p ssh_args
system(Shellwords.join(ssh_args))

これをforward-docker-portsとして置いておいて

$ chmod +x forward-docker-ports
$ FORWARD_DOCKER_PORTS_SSH_HOST=100.x.x.x forward-docker-ports

再度、kubectl cluster-infoを試すと

$ kubectl cluster-info --context kind-kind
Kubernetes master is running at https://127.0.0.1:x
KubeDNS is running at https://127.0.0.1:x/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

とりあえずkindも動いたので、Kubernetesコントローラーの開発とかできそう。

Rubyを入れる。Big Surにデフォルトで入ってるRubyは

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.arm64e-darwin20]

arm64のRuby 2.7を入れたい。
rbenv + ruby-buildをいれる。bashスクリプトなのでHomebrewで入れてもアーキテクチャの問題はない気もするけど、一応git cloneしてインストールした。
rbenvがダウンロードしてくるOpenSSLがdarwin arm64に対応してないので、MacPortsで入れる:

$ sudo port install openssl

また、以下のエラーが出るので、readlineもMacPortsで入れとく:

readline.c:1904:37: error: use of undeclared identifier 'username_completion_function'; did you mean 'rl_username_completion_function'?
$ sudo port install readline

で、

$ export RUBY_CONFIGURE_OPTS="--with-openssl-dir=/opt/local --with-readline-dir=/opt/local"
$ rbenv install 2.7.2
$ rbenv global 2.7.2
$ ruby -v
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [arm64-darwin20]

Ruby 2.7.2 amd64版をインストールする。
↑でビルドしたRubyをuniversal binaryにすることも考えたけど、native extensionのgemいれるともう一方のarchで動かない、とか発生しそうなので分けてインストールしてみる(Big Surにデフォルトで入ってるRubyはuniversal binaryだけどどうなってるんだろう。要検証)

$ cp ~/.rbenv/plugins/ruby-build/share/ruby-build/2.7.2 work/2.7.2-amd64
$ arch -x86_64 rbenv install ~/work/2.7.2-amd64
...
Installed ruby-2.7.2 to /Users/ryotarai/.rbenv/versions/2.7.2-amd64

インストールできた

$ arch
arm64
$ rbenv shell 2.7.2-amd64
$ ruby -v
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin20]
作成者以外のコメントは許可されていません