- 投稿日:2020-12-12T22:41:13+09:00
Macbook Pro M1(Apple Silicon) で Dockerを動かす
準備
※英語わかんなくてもなんとかなります。
- DockerのDeveloper Preview Programに参加する
- Docker Community Slackに参加する
- Developer Preview Program の案内メールが来るのでDocker Community SlackのDisplay Nameを伝える
- #dev-preview-programに招待される
- #dev-preview-programのpin付けされているメッセージを読んでDokcerのPreview5を入手する
- ここのメッセージに注意事項もセットで記載されてます
ここから先は特に特殊なことは書いてないです。
インストール
- dmgファイルを実行
- いつもの手順でApplicationsへ入れる(PREVIEWマーク付いてる!)
コンテナ起動
- Docker.appを実行
- 特に問題発生せず
その他
- あっけなく動いてしまった
- 時間かかるのはPreview版を入手するところまで
- 動かないイメージはちらほら(手元で使ってたものは3割動かなかった)
- 投稿日:2020-12-12T22:06:38+09:00
ubuntu 20.04.1 上でdockerを使うための設定スクリプト (プロキシ切り替え対応)
ubuntu 20.04.1 上でdockerを使うための設定スクリプト (プロキシ切り替え対応)
ubuntu 20.04.1 上でプロキシ環境でdockerを使うための設定スクリプト という記事を書きましたが、プロキシなし環境に切り替えることができるスクリプトを作成しました。
スクリプト
https://gist.github.com/m-tmatma/7556d81a850a8145ded7074578722334
準備
setup-docker.pyという名前で保存します。chmod +x setup-docker.pyで実行権限を付けます。使い方
ヘルプ
$ ./setup-docker.py usage: sudo ./setup-docker.py set http://proxy:port sudo ./setup-docker.py noproxy指定したプロキシを設定する
http://192.168.11.61:3128に設定する場合sudo ./docker-proxy.py http://192.168.11.61:3128プロキシなしでアクセスする場合
sudo ./docker-proxy.py noproxyスクリプト本体
https://gist.github.com/m-tmatma/7556d81a850a8145ded7074578722334
#!/usr/bin/python3 import string import subprocess import os import sys ########################################################################### # template for /etc/apt/apt.conf ########################################################################### template_apt_conf = """\ Acquire::http::Proxy "$http_proxy_url"; Acquire::https::Proxy "$https_proxy_url"; """ ########################################################################### # template for /etc/systemd/system/docker.service.d/override.conf ########################################################################### template_docker_service_override = """\ [Service] Environment="HTTP_PROXY=$http_proxy_url" Environment="HTTPS_PROXY=$https_proxy_url" Environment="NO_PROXY=localhost,127.0.0.1" """ ########################################################################### # template for ~/.docker/config.json ########################################################################### template_config_json = """\ { "proxies": { "default": { "httpProxy": "$http_proxy_url", "httpsProxy": "$https_proxy_url", "noProxy": "localhost,127.0.0.1" } } } """ ########################################################################### # write proxy data to a file ########################################################################### def write_proxy(file_name, input_template, http_proxy_url, https_proxy_url): if http_proxy_url or https_proxy_url: context = { 'http_proxy_url' : http_proxy_url, 'https_proxy_url' : https_proxy_url } template = string.Template(input_template) data = template.substitute(context) with open(file_name, "w") as fout: fout.write(data) print("wrote: " + file_name) else: if os.path.exists(file_name): os.unlink(file_name) print("removed: " + file_name) ########################################################################### # get the home directory of the original user ########################################################################### def get_original_home(): user = os.environ['SUDO_USER'] if user: home_dir = os.path.expanduser('~' + user) else: home_dir = os.path.expanduser('~') return home_dir ########################################################################### # write etc/apt/apt.conf ########################################################################### def write_apt_conf(http_proxy_url, https_proxy_url): write_proxy('/etc/apt/apt.conf', template_apt_conf, http_proxy_url, https_proxy_url) ########################################################################### # write /etc/systemd/system/docker.service.d/override.conf ########################################################################### def write_docker_service_override(http_proxy_url, https_proxy_url): docker_service_d = '/etc/systemd/system/docker.service.d' if not os.path.isdir(docker_service_d): os.mkdir(docker_service_d) override_conf = os.path.join(docker_service_d, "override.conf") write_proxy(override_conf, template_docker_service_override, http_proxy_url, https_proxy_url) ########################################################################### # write ~/.docker/config.json ########################################################################### def write_docker_config(http_proxy_url, https_proxy_url): # get the path of ~/.docker home_dir = get_original_home() docker_dir = os.path.join(home_dir, ".docker") # create ~/.docker if not os.path.isdir(docker_dir): os.mkdir(docker_dir) # get ~/.docker/config.json config_json = os.path.join(docker_dir, "config.json") write_proxy(config_json, template_config_json, http_proxy_url, https_proxy_url) ########################################################################### # usage ########################################################################### def usage(): script = sys.argv[0] print("usage:") print("sudo " + script + " set http://proxy:port") print("sudo " + script + " noproxy") def exec(command): subprocess.call(command.split(), shell=False) print("ran: " + command) if __name__ == '__main__': if len(sys.argv) < 2 or os.getuid() != 0: usage() sys.exit(1) http_proxy_url = None https_proxy_url = None cmd = sys.argv[1] if cmd == "set": if len(sys.argv) == 3: http_proxy_url = sys.argv[2] https_proxy_url = sys.argv[2] else: usage() sys.exit(1) elif cmd == "noproxy": pass else: usage() sys.exit(1) exec('apt install -y docker.io docker-compose') write_apt_conf(http_proxy_url, https_proxy_url) write_docker_service_override(http_proxy_url, https_proxy_url) write_docker_config(http_proxy_url, https_proxy_url) exec('systemctl daemon-reload') exec('systemctl restart docker')
- 投稿日:2020-12-12T20:01:44+09:00
Raspberry Pi4 3台でKubernetesクラスタ構築
ALHアドベントカレンダー2020
12/12(土)はきくりんが担当いたします!!
サーバー、スイッチ、電源、筐体の選定から、組み込み、構築、ナレッジ化とインフラエンジニア総合格闘技的な内容となりました。
目的と背景
ずっとやろうと思っていたラズパイのクラスタ構成を使ったKubernetesの構築ですがこの度ついに着手出来たので情報まとめていきます。
とりあえずクラスタ構成の構築と、webサーバが上がることをゴールとします。
今回クラスタケースの収容数が4つのため、既に持っていたラズパイ3も収容したいと思います。
スイッチングハブと充電器も収容することを考えると3台がMAXだよね、ということに組んでから気付いたので3台構成とします。
一部写真で同居していますがまあ気にしないでください。構築・ハードウェア編
準備したもの
・新規購入
※主張の激しいマウスは無関係です。
・後で追加+家に転がってたもの
一覧(工具類は割愛)
パーツ名 詳細 備考 Raspberry Pi4 Raspberry Pi 4 Model B/4GB x 3台 k8sクラスタ用 Raspberry Pi3Raspberry Pi 3 Model B?/1GB x 1台検証用、3台構成に変更したので、結局使わなかった Raspberry Pi用ヒートシンク Akuoly Raspberry Piアルミ製ヒートシンクセット ラズベリーパイ冷却キットクーラーheatsink 15点セット x2 k8sクラスタ用、どうやら3向けだったみたいで1セット SDカード Samsung micro SDXC 64GB MB-MC64GA x 3枚 k8sクラスタ用 スイッチングハブ BUFFALO Giga対応 プラスチック筐体 AC電源 5ポート LSW6-GT-5EPL/NBK ブラック スイッチングハブ ローコストモデル 簡易 スイッチングハブロジテック 1000BASE-T対応 スイッチングハブ LAN-GSW05PSBE廃盤のため中古。買ってから3ポートしか無いことに気づき、結局使わなかった ケース GeeekPi Raspberry Piクラスタケース(4層) 冷却ファン EASYDIY 120mm PWM 高風量静音デュアルフレーム白色LEDケースファン ケース付属が虹色に光るのが嫌なので ファンコントローラ サイズ ファンコン搭載 ファン用USB変換ケーブル AS-71G2 風量とLEDの光量調節用 USB充電器 Anker PowerPort Speed 5 電源ケーブル SANWA SUPPLY(サンワサプライ) 電源コード KB-DM2L-2 ケースに充電器を収容するためにL字プラグのもの USBケーブル SUNGUY type-A & type-c 30cm 2本セット x 2セット(4本) ラズパイ給電用 USBケーブルAnker PowerLine+ Micro USBケーブル検証ラズパイを載せるのはやめたので、付属のケーブルタイだけ使用 USBケーブル USB 電源ケーブル 変換プラグ付き DC充電コード スイッチングハブ給電用 LANケーブル ミヨシMCO カテゴリ-6スリムLANケ-ブル 15cm x 4本 ハブ~ラズパイ間接続 ケーブル用ベルト面ファスナー配線ベルト,面ファスナー配線ベルト固定ベルト付きDAISOで調達、結局使わなかった HDMI変換 ホーリック HDMIマイクロ変換アダプタ 7cm シルバー HDM07-042ADS 初期構築時に使用 キッティング
ラズパイを箱から出してヒートシンクを貼っていきます
GeekPi クラスタケースに収容していきます。
ラズパイにmicrosdの付属のライザーカードをつけたあとアクリルボードの保護シートを剥がして固定します。
このカードをかませることで分解せずともケース後方からmicrosdの抜き差しが可能になります。(単一障害点が増えるけど)
最初からネジをすべて締めるとなかなか入って行かず基板を破損させてしまいそうになるので、緩めの状態ですべてネジを通してから固定させると付けやすいです。
CPUクーラーにもアクリルボードを取り付けます。
サイドパネルに差し込みます。方向が違うと刺さらないようになってますね。※写真では4つラズパイ使ってますが後で1台外しています。
全体図
全て取り付けるとこんな感じです。
今回はubuntuを使うのでcanonicalの中の人に貰ったステッカーでも貼っておきます。
充電器からの給電なは左から冷却ファン、スイッチングハブ、ラズパイx3 です。
構築・ソフトウェア編
OSインストール (全台で実行)
今回はUbntu Server 20.04 LTS(arm64)を使っていきます。
$ cat /etc/os-release NAME="Ubuntu" VERSION="20.04.1 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.1 LTS" VERSION_ID="20.04" #(以下省略)事前にubuntu desktop 20.04 LTS(amd64)で検証したのですが、k8sの導入でコケました。
また、今後8GBモデルを買った際にmicrosdを差し替えて移行することも考えられるので、raspberry pi OSではなく64bit版があるubuntuにしました。
純正の書き込みツールでmicroSDにOSを書き込んでいきます。microsdはPCに挿しておきます。
Raspberry Pi OS – Raspberry Pi Imager から環境に合ったものをダウンロードします。
※この記事ではWindowsでやっています。
起動すると以下の画面になります。Operating System>[CHOOSE OS]からmicrosdに書き込むOSを選択します。
Ubuntuを選択
Ubuntu Server 20.04.1 LTS(RPi3/4)を選択
OSが選択されましたね。次はSD Card>[CHOOSE SD CARD]からmicrosdを選択します。
挿しておいたmicrosdを選択します。名前はmicrosdの種類やロットで変わると思いますので容量で判断かなあ。
余談ですがpanasonic製microsdフォーマットツールとかだとmicrosd以外のストレージも選択出来てしまうので誤ってフォーマットしてしまうことがありました。
まあ余計なものは取り外ししておいたほうがいいですね。
[WRITE]を選択
中身全部消えるけどええんか?という確認が出ます。確認して[YES]を選択
10分~20分待ちます。microssdの書き込み速度で変わると思います。
書き込みが終わると。「書き込みが終わったんで抜いていいっす」というダイアログが出るので[CONTINUE]を選択して閉じます。
3台分やったら終わりです。OS初期設定 (全台で実行)
前段作業で書き込んだmicrosdをrasberry piへ差し込み、起動させます。
raspberry piは給電されると自動的に電源が入ります。自分の場合は1台ずつ電源を入れて設定していきました。
設定対象のraspberry piにmicro HDMI端子↔HDMI変換ケーブルを挿してモニタで作業します。(今回は検証用のケーブルを引き回してあるTV使いました。)
ubuntu serverでは初期設定でGUIは無効化、SSHが有効化してあります。ubuntu desktopではgnomeが起動、sshはインストールされていない
コマンドラインが走り、ubuntu login:と出れば起動完了です。
初期パスワード変更
ubuntuユーザーの初期パスワードはubuntuで、ログインするとパスワード変更を即されるので変更します。
キーボードが英字設定なので記号などを含めるのは気をつけたほうがいいです。
後で日本語設定入れてからpasswordコマンド使えばいいので、仮でいい気がします。ipアドレスを確認
$ ip a #(中省略) 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether XX:XX:XX:XX:XX:ac brd ff:ff:ff:ff:ff:ff inet 192.168.0.5/24 brd 192.168.0.255 scope global eth0 #(以下省略)eth0の結果を確認すればいいので結果が上記の場合
192.168.0.5がDHCPで自動的に割あたったIPですね。★以下の手順以降はPCからSSHクライアント(Teraterm等)から操作します。★
【全ノードで実行】ビルトインアカウント無効化と作業アカウント(きくりんユーザー)作成
## きくりんユーザー作成 $ sudo useradd -m -s /usr/bin/bash kickling aaaa ## きくりんユーザーパスワード設定 $ sudo passwd kickling ## きくりんユーザーをsudo権限付与 $ sudo adduser kickling sudo ## きくりんユーザーをsudo権限付与確認 $ cat /etc/group | grep sudo sudo:x:27:ubuntu,kickling ## ビルトイン(ubuntu)をログイン無効化 $sudo usermod -s /usr/sbin/nologin ubuntu ## 無効化(nologin)確認 $ cat /etc/passwd | grep ubuntu【管理ノードで実行】管理ノードのネットワーク設定
ホスト名設定
## ホスト名設定 $ sudo hostnamectl set-hostname ras-k8s-master1 ## ホスト名確認 $ hostname ras-k8s-master1ipアドレス(ネットワーク)設定
## ホスト名設定 $ sudo nano /etc/netplan/99-network.yaml ##--ここから-- network: version: 2 renderer: networkd ethernets: eth0: dhcp4: false dhcp6: false addresses: - 192.168.0.71/24 gateway4: 192.168.0.1 nameservers: addresses: - 192.168.0.1 ##--ここまでコピーアンドペースト-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## 設定適用 $ sudo netplan apply ##SSHが切断されるので設定したIPでログインし直す【ワーカーノード1で実行】ワーカーノード1のネットワーク設定
ホスト名設定
## ホスト名設定 $ sudo hostnamectl set-hostname ras-k8s-worker1 ## ホスト名確認 $ hostname ras-k8s-worker1ipアドレス(ネットワーク)設定
## ホスト名設定 $ sudo nano /etc/netplan/99-network.yaml ##--ここから-- network: version: 2 renderer: networkd ethernets: eth0: dhcp4: false dhcp6: false addresses: - 192.168.0.72/24 gateway4: 192.168.0.1 nameservers: addresses: - 192.168.0.1 ##--ここまでコピーアンドペースト-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## 設定適用 $ sudo netplan apply ##SSHが切断されるので設定したIPでログインし直す【ワーカーノード2で実行】ワーカーノード2のネットワーク設定
ホスト名設定
## ホスト名設定 $ sudo hostnamectl set-hostname ras-k8s-worker2 ## ホスト名確認 $ hostname ras-k8s-worker2ipアドレス(ネットワーク)設定
## ホスト名設定 $ sudo nano /etc/netplan/99-network.yaml ##--ここから-- network: version: 2 renderer: networkd ethernets: eth0: dhcp4: false dhcp6: false addresses: - 192.168.0.73/24 gateway4: 192.168.0.1 nameservers: addresses: - 192.168.0.1 ##--ここまでコピーアンドペースト-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## 設定適用 $ sudo netplan apply ##SSHが切断されるので設定したIPでログインし直す【全ノードで実行】共通OS設定
一通りネットワーク設定が終わったので接続し直します。
ホスト名 IPアドレス ログインユーザ ras-k8s-master1 192.168.0.71 kickling ras-k8s-worker1 192.168.0.72 kickling ras-k8s-worker2 192.168.0.73 kickling hostsファイルへ追記
## hosts編集 $ sudo nano /etc/netplan/99-network.yaml ##--ここから-- # Kubernetes Clusters 192.168.0.71 k8s-master1 ras-k8s-master1 192.168.0.72 k8s-worker1 ras-k8s-worker1 192.168.0.73 k8s-worker2 ras-k8s-worker2 ##--ここまで下に追記-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## hosts確認 $ cat /etc/hostsswapの無効化
Docker及びKubernetesの実行時はswapの無効化が必要になるのですが
$ free total used free shared buff/cache available Mem: 3884348 945272 1677080 5184 1261996 3001004 Swap: 0 0 0 # ←全て0最初から無効化されていました。大抵の場合有効になってるはずなので
swap offしてreboot
してあげる必要があると思います。time zone変更
$ sudo timedatectl set-timezone Asia/Tokyo $ timedatectl | grep Time Time zone: Asia/Tokyo (JST, +0900)key map変更
$ sudo localectl set-keymap jp106 $ localectl System Locale: LANG=C.UTF-8 VC Keymap: jp106 X11 Layout: jp X11 Model: jp106 X11 Options: terminate:ctrl_alt_bkspIPv6の無効化(任意)
## sysctl.conf編集 $ sudo nano /etc/sysctl.conf ##--ここから-- net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.eth0.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 ##--ここまで下に追記-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## カーネルパラメータ反映 $ sudo sysctl -p ## ipv6無効化確認(inet6が表示されないこと) $ ip aパッケージの更新
$ sudo apt update $ sudo apt -y upgradecgruop でmemoryの有効化
Ubuntu Server 20.04.1 LTS(RPi3/4)ではデフォルトで無効化されているようです。
↓3列目が0 = enableが無効$ cat /proc/cgroups | grep memory memory 0 105 0/boot/firmware/cmdline.txt に追記します。
1行目に追記します。全一行のファイルなので改行して行追加とかでは無いです。
記法間違えると再起動後に上がってこないかも## cmdline.txt編集 $ sudo nano /boot/firmware/cmdline.txt ##--ここから--(1文字目はスペース) cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory ##--ここまで1行目の最後に追記-- #ctrl + xで保存、yでファイル名指定(変えなくていい)、Enterで閉じる ## cmdline.txt確認 $ cat /boot/firmware/cmdline.txt net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory ## 設定反映のため、再起動 $ sudo reboot再起動後、確認
↓3列目が1 = enableが1なので有効になってますね。$ cat /proc/cgroups | grep memory memory x x 1iptableがのnftablesバックエンドを参照しないようにする
$ sudo apt-get -y install iptables arptables ebtables $ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy $ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy $ sudo update-alternatives --set arptables /usr/sbin/arptables-legacy update-alternatives: using /usr/sbin/arptables-legacy to provide /usr/sbin/arptables (arptables) in manual mode $ sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy update-alternatives: using /usr/sbin/ebtables-legacy to provide /usr/sbin/ebtables (ebtables) in manual modeDockerのインストール
## 6行まとめてコピーアンドペーストで貼り付けて実行する $ sudo apt-get -y install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common ## リポジトリキー追加 $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - ## arm64向けDockerリポジトリ追加 $ sudo add-apt-repository "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" $ sudo apt-get update $ sudo apt-get -y install docker-ce docker-ce-cli containerd.io ## Docker関連バージョン固定設定 $ sudo apt-mark hold docker-ce docker-ce-cli containerd.io docker-ce set on hold. docker-ce-cli set on hold. containerd.io set on hold.作業ユーザーをDockerグループに追加
$ sudo adduser kicking docker Adding user `kickling' to group `docker' ... Adding user kickling to group docker Done. $ cat /etc/group | grep docker # 確認する docker:x:998:kicklingグループ割当を反映させるため一旦
exitで抜けてログインし直します。Dockerのバージョン確認(任意)
$ docker version Client: Docker Engine - Community Version: 19.03.14 API version: 1.40 Go version: go1.13.15 Git commit: 5eb3275 Built: Tue Dec 1 19:20:49 2020 OS/Arch: linux/arm64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.14 API version: 1.40 (minimum version 1.12) Go version: go1.13.15 Git commit: 5eb3275 Built: Tue Dec 1 19:19:19 2020 OS/Arch: linux/arm64 Experimental: false containerd: Version: 1.3.9 GitCommit: ea765aba0d05254012b0b9e595e995c09186427f runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683Dockerの動作確認(Hello worldコンテナの起動)
""Hello from Docker!""と表示されればOKです。$ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 256ab8fe8778: Pulling fs layer 256ab8fe8778: Downloading 424B/3.367kB256ab8fe8778: Downloading 3.367kB/3.367kB256ab8fe8778: Download complete 256ab8fe8778: Extracting 3.367kB/3.367kB256ab8fe8778: Extracting 3.367kB/3.367kB256ab8fe8778: 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. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (arm64v8) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/Kubernetesのインストール
kubeadm、kubectl、kubeletをインストールします。
$ sudo apt-get update && sudo apt-get -y install apt-transport-https curl $ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - $ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF $ sudo apt-get update $ sudo apt-get -y install kubelet kubeadm kubectl ## kubelet kubeadm kubectlのバージョン固定 $ sudo apt-mark hold kubelet kubeadm kubectl kubelet set on hold. kubeadm set on hold. kubectl set on hold.各モジュールのバージョン確認
$ kubeadm version -o json { "clientVersion": { "major": "1", "minor": "19", "gitVersion": "v1.19.4", "gitCommit": "d360454c9bcd1634cf4cc52d1867af5491dc9c5f", "gitTreeState": "clean", "buildDate": "2020-11-11T13:15:05Z", "goVersion": "go1.15.2", "compiler": "gc", "platform": "linux/arm64" } } $ kubectl version -o json { "clientVersion": { "major": "1", "minor": "19", "gitVersion": "v1.19.4", "gitCommit": "d360454c9bcd1634cf4cc52d1867af5491dc9c5f", "gitTreeState": "clean", "buildDate": "2020-11-11T13:17:17Z", "goVersion": "go1.15.2", "compiler": "gc", "platform": "linux/arm64" } } The connection to the server localhost:8080 was refused - did you specify the right host or port? $ kubelet --version Kubernetes v1.19.4Kubernetes クラスタの設定
【管理ノードで実行】Master Nodeの初期化
k8sクラスタの初期化作業を実行します。
オプション名 値 備考 apiserver-advertise-address 192.168.0.71 管理ノードのIP pod-network-cidr 10.244.0.0/16 ポッド(flannel)のアドレス帯域指定 $ sudo kubeadm init --apiserver-advertise-address=192.168.0.71 --pod-network-cidr=10.244.0.0/16 [sudo] password for kickling: W1205 09:15:19.362924 2871 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io] [init] Using Kubernetes version: v1.19.4 [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/ [WARNING SystemVerification]: missing optional cgroups: hugetlb [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local ras-k8s-master1] and IPs [10.96.0.1 192.168.0.71] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [localhost ras-k8s-master1] and IPs [192.168.0.71 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [localhost ras-k8s-master1] and IPs [192.168.0.71 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Starting the kubelet [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 35.013277 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node ras-k8s-master1 as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node ras-k8s-master1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: g9yaoj.xs04rxh4avt5mikd [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.0.71:6443 --token g9yaoj.xs04rxh4avt5mikd \ --discovery-token-ca-cert-hash sha256:52488ac2af018a489aae35d55ead8ad784b0593a0db5c8ad79a16505cb30e1d3最後の2行の
kubeadm join 192.168.0.71:6443 --token g9yaoj.xs04rxh4avt5mikd \は
--discovery-token-ca-cert-hash sha256:52488ac2af018a489aae35d55ead8ad784b0593a0db5c8ad79a16505cb30e1d3
Worker Node追加時に必要なコマンドになるのでメモっておきましょう。トークンが有効なのは24時間なので、過ぎた場合はコマンドで再発行が必要です。
※この時点で後述のkubeadm token list及びkubeadm token create打つとエラーになります
ので次に環境変数設定と入力補完設定を済ませます。残り時間を確認する場合は
kubeadm token listコマンドを実行してTTLの列を確認します。
何も表示されない場合は有効なトークンが無いのでkubeadm token createコマンドで生成します。【管理ノードで実行】環境変数と入力補完の設定
環境変数設定
$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config $ echo 'KUBECONFIG=$HOME/.kube/config' >> $HOME/.bashrc $ source $HOME/.bashrc # kubectlコマンド実行時「The connection to the server ・・・」が表示されないことを確認する $ kubectl version -o json入力補完設定
$ source <(kubectl completion bash) $ echo "source <(kubectl completion bash)" >> $HOME/.bashrc【管理ノードで実行】Podネットワークアドオンのインストール
Pod間の通信を行うためにflannelを設定します。
$ curl https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml -O $ kubectl apply -f kube-flannel.yml podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds createdflannelの起動を確認します。
kube-flannel-ds-xxxが確認できればOKです。数秒かかりました。$ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-f9fd979d6-lhddv 0/1 Running 0 7m12s coredns-f9fd979d6-qxpkl 1/1 Running 0 7m12s etcd-ras-k8s-master1 1/1 Running 0 7m17s kube-apiserver-ras-k8s-master1 1/1 Running 0 7m17s kube-controller-manager-ras-k8s-master1 1/1 Running 0 7m17s kube-flannel-ds-gr226 1/1 Running 0 47s kube-proxy-r2lsh 1/1 Running 0 7m12s kube-scheduler-ras-k8s-master1 1/1 Running 0 7m17s【管理ノードで実行】LoadBalancer(MetalLB) のインストール
MetalLBはControllerとSpeakerの2種類のPodで構成されてます。
$ curl https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/namespace.yaml -o namespace.yaml $ curl https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/metallb.yaml -o metallb.yaml $ kubectl apply -f namespace.yaml namespace/metallb-system created $ kubectl apply -f metallb.yaml podsecuritypolicy.policy/controller created podsecuritypolicy.policy/speaker created serviceaccount/controller created serviceaccount/speaker created clusterrole.rbac.authorization.k8s.io/metallb-system:controller created clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created role.rbac.authorization.k8s.io/config-watcher created role.rbac.authorization.k8s.io/pod-lister created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created rolebinding.rbac.authorization.k8s.io/config-watcher created rolebinding.rbac.authorization.k8s.io/pod-lister created daemonset.apps/speaker created deployment.apps/controller created $ kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" secret/memberlist createdMetalLBの起動を確認します。
controller-xxx-xxx と speaker-xxxが確認できればOKです。
controllerはPendingになっていますが、worker nodeを登録後にRunningになります。$ kubectl get pod -n metallb-system NAME READY STATUS RESTARTS AGE controller-8687cdc65-s77qq 0/1 Pending 0 55s speaker-cd548 1/1 Running 0 55s【ワーカーノード1,ワーカーノード2で実行】Worker nodeをクラスタに追加する
ワーカーノードを登録してクラスタ化します。
"【管理ノードで実行】Master Nodeの初期化"でメモっておいた、
kubeadm join 192.168.0.71:6443 --token g9yaoj.xs04rxh4avt5mikd \
--discovery-token-ca-cert-hash sha256:52488ac2af018a489aae35d55ead8ad784b0593a0db5c8ad79a16505cb30e1d3
の先頭にsudoを付けてワーカーノードで実行します。$ sudo kubeadm join 192.168.0.71:6443 --token g9yaoj.xs04rxh4avt5mikd \ --discovery-token-ca-cert-hash sha256:52488ac2af018a489aae35d55ead8ad784b0593a0db5c8ad79a16505cb30e1d3 [sudo] password for kickling: [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/ [WARNING SystemVerification]: missing optional cgroups: hugetlb [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.プロンプトが返ってくるまでしばらく待ちます。
【管理ノードで実行】Worker nodeのクラスタ追加を確認
Master nodeで確認します。
ras-k8s-worker1とras-k8s-worker2がReadyになってれば大丈夫ですね。
また、MetalLBのcontrollerがPendingからRunningになりました。$ kubectl get nodes NAME STATUS ROLES AGE VERSION ras-k8s-master1 Ready master 12m v1.19.4 ras-k8s-worker1 Ready <none> 100s v1.19.4 ras-k8s-worker2 Ready <none> 75s v1.19.4 $ kubectl get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-f9fd979d6-lhddv 1/1 Running 0 12m kube-system coredns-f9fd979d6-qxpkl 1/1 Running 0 12m kube-system etcd-ras-k8s-master1 1/1 Running 0 12m kube-system kube-apiserver-ras-k8s-master1 1/1 Running 0 12m kube-system kube-controller-manager-ras-k8s-master1 1/1 Running 0 12m kube-system kube-flannel-ds-bbgrn 1/1 Running 0 2m2s kube-system kube-flannel-ds-gr226 1/1 Running 0 5m42s kube-system kube-flannel-ds-mcfw9 1/1 Running 0 97s kube-system kube-proxy-gsmwm 1/1 Running 0 97s kube-system kube-proxy-p6szf 1/1 Running 0 2m2s kube-system kube-proxy-r2lsh 1/1 Running 0 12m kube-system kube-scheduler-ras-k8s-master1 1/1 Running 0 12m metallb-system controller-8687cdc65-s77qq 1/1 Running 0 3m40s metallb-system speaker-cd548 1/1 Running 0 3m40s metallb-system speaker-cs6p4 1/1 Running 0 61s metallb-system speaker-z75xl 1/1 Running 0 46s【管理ノードで実行】Worker Nodeにラベルを設定する
$ kubectl label node ras-k8s-worker1 node-role.kubernetes.io/worker=worker node/ras-k8s-worker1 labeled $ kubectl label node ras-k8s-worker2 node-role.kubernetes.io/worker=worker node/ras-k8s-worker2 labelednode/ras-k8s-worker2 labeled #ROLESを確認する $ kubectl get nodes NAME STATUS ROLES AGE VERSION ras-k8s-master1 Ready master 21m v1.19.4 ras-k8s-worker1 Ready worker 11m v1.19.4 ras-k8s-worker2 Ready worker 11m v1.19.4Kubernetes で コンテナを動かす
Docker が動作しているホストのHostnameを表示するNginxコンテナ - Qiita
を参考に、どのノードと接続しているのか確認していきます。
yamlをエディタで作成します。display-hostname.yamlapiVersion: v1 kind: Namespace metadata: name: nginx-prod --- apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: pool-ips # MetallbのIPプール名 protocol: layer2 addresses: - 192.168.0.211-192.168.0.215 --- apiVersion: v1 kind: Service metadata: name: nginx-service-lb # Service(LoadBalancer) の名前 namespace: nginx-prod annotations: metallb.universe.tf/address-pool: pool-ips # MetallbのIPプール名 spec: type: LoadBalancer ports: - name: nginx-service-lb protocol: TCP port: 8080 # ServiceのIPでlistenするポート nodePort: 30080 # nodeのIPでlistenするポート(30000-32767) targetPort: 80 # 転送先(コンテナ)でlistenしているPort番号のポート selector: # service のselctorは、matchLabels 扱いになる app: nginx-pod # 転送先の Pod のラベル --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment # Deployment の名前(ReplicaSetの名前もこれになる) namespace: nginx-prod spec: selector: matchLabels: # ラベルがマッチしたPodを対象とするReplicaSetの作成 app: nginx-pod replicas: 2 template: # Pod のテンプレート metadata: name: nginx-pod # Pod の名前 namespace: nginx-prod labels: # Pod のラベル app: nginx-pod spec: containers: # コンテナの設定 - name: nginx-container # コンテナの名前 image: yasthon/nginx-display-hostname # イメージの名前 env: - name: nginx-container ports: - containerPort: 80 # コンテナのポート volumeMounts: - name: file-hostname mountPath: /usr/share/nginx/html/hostname volumes: - name: file-hostname hostPath: path: /etc/hostnameリソースを作成します。
Pod、Service、Deployment、ReplicaSet、ConfigMapの作成を確認します。
ServiceのEXTERNAL-IPは、IPプールから割り当たっています。$ kubectl apply -f display-hostname.yaml namespace/nginx-prod created configmap/config created service/nginx-service-lb created deployment.apps/nginx-deployment created kickling@ras-k8s-master1:~$ kubectl get all -n nginx-prod NAME READY STATUS RESTARTS AGE pod/nginx-deployment-7ff4cc65cd-nvchj 0/1 ContainerCreating 0 19s pod/nginx-deployment-7ff4cc65cd-zlwnv 0/1 ContainerCreating 0 19s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/nginx-service-lb LoadBalancer 10.102.181.109 192.168.100.211 8080:30080/TCP 19s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 0/2 2 0 19s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-7ff4cc65cd 2 2 0 19s #確認する $ kubectl get configmap -n metallb-system NAME DATA AGE config 1 47sServiceの詳細情報から、LoadBalancer Ingress とPortの値を確認します。
$ kubectl describe svc nginx-service-lb -n nginx-prod Name: nginx-service-lb Namespace: nginx-prod Labels: <none> Annotations: metallb.universe.tf/address-pool: pool-ips Selector: app=nginx-pod Type: LoadBalancer IP: 10.102.181.109 LoadBalancer Ingress: 192.168.100.211 Port: nginx-service-lb 8080/TCP TargetPort: 80/TCP NodePort: nginx-service-lb 30080/TCP Endpoints: 10.244.1.3:80,10.244.2.2:80 Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal IPAllocated 58s metallb-controller Assigned IP "192.168.100.211" Normal nodeAssigned 42s metallb-speaker announcing from node "ras-k8s-worker1" Normal nodeAssigned 32s metallb-speaker announcing from node "ras-k8s-worker2"接続確認
LoadBalancer IngressのIPアドレスとPortのポート番号へcurlして接続確認します。
$ curl 192.168.0.211:8080/index.sh <html><head> <title>ras-k8s-worker2</title> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> </head><body> HOSTNAME : ras-k8s-worker1 </body></html>何度か繰り返すと接続先がras-k8s-worker2になったりras-k8s-worker1に戻ったりして
LBで振り分けされていることがわかります。抜線確認
ワーカーノード2のLANケーブルを抜きます。
ras-k8s-worker2の振り分けは停止して、ras-k8s-worker1へ接続のみになることが確認できます。$ curl 192.168.0.211:8080/index.sh <html><head> <title>ras-k8s-worker2</title> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> </head><body> HOSTNAME : ras-k8s-worker1 </body></html> $ curl 192.168.0.211:8080/index.sh <html><head> <title>ras-k8s-worker2</title> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> </head><body> HOSTNAME : ras-k8s-worker1 </body></html> ##ノード一覧を確認するとras-k8s-worker2はNotReadyになっています $ kubectl get nodes NAME STATUS ROLES AGE VERSION ras-k8s-master1 Ready master 44m v1.19.4 ras-k8s-worker1 Ready worker 34m v1.19.4 ras-k8s-worker2 NotReady worker 34m v1.19.4結線し直すと戻ります。
ブラウザからは
http://192.168.0.211:8080/index.shで確認できます。所感
後述する先駆者様の写経がベースとなりましたが、環境差分やマークダウン記法が初めてなこともあり
結構書き直しの部分が大半で勉強になりました。
また、Kubernetesの構築は何度も挑戦するもkubeletの初期化エラーにぶつかり挫折しかけていたので
今回ついにKubernetesの実機環境ができあがって非常に嬉しいです。
今はなんとなくよくわからんがなんか出来た状態なので少しづつ検証して仕組みを勉強したいと思います。以上、k8sクラスタ構築とwebサーバの動確まで でした。
参考
kubeadmを使ってクラスターを構築する | Kubernetes
RaspberryPi 4 にUbuntu20.04 をインストールして、Kubernetes を構築してコンテナを動かす - Qiita
3台のRaspberry Pi 4でKubernetesクラスターを構築する(Ubuntu Server 20.04 LTS 64bit) | kimama.cloud
Docker が動作しているホストのHostnameを表示するNginxコンテナ - Qiita
MetalLB, bare metal load-balancer for Kubernetes
KubernetesロードバランサーのMetalLBを導入した話(Necoプロジェクト体験入部) - Cybozu Inside Out | サイボウズエンジニアのブログ
Markdown記法 サンプル集 - Qiita
Raspberry Piでkubernetesクラスタを組む | SIOSDX | コンテナの窓口
- 投稿日:2020-12-12T17:22:10+09:00
簡単にDockerでreact環境を速攻で作る
こんにちは、IT技術者の田中です。
簡単にDockerでreact環境を速攻で作る背景
Dockerでreact環境を速攻で作る最新(2020年12月12日)情報がなく困ったので、記事を書きました!
(色々惜しい記事はありましたが、ちょこちょこミスがあり困りました)前提としてはmacbook proで構築しました!
フォルダ構成
下記のフォルダ構成で作ります。
react
├ Dockerfile
├ docker-compose.yml
└ react-sample/Dockerfile
Dockerfileの内容
FROM node:15.3.0-alpine WORKDIR /usr/src/appdocker-compose.yml
docker-compose.ymlの内容
version: '3' services: node: build: context: . dockerfile: Dockerfile volumes: - ./:/usr/src/app command: sh -c "cd react-sample && yarn start" ports: - "3000:3000"dockerビルドを実行する
docker-compose.ymlのフォルダに移動します。
> docker-compose build上記が完了するまで待ちます。
docker-composeでreactをプロジェクト作成
下記のコマンドで、reactのプロジェクトを作成する。
> docker-compose run --rm node sh -c "npm install -g create-react-app && create-react-app react-sample"dockerのコンテナを起動する
下記のコマンドでdockerコンテナを起動する。
docker-compose upreactの起動を確認する
ブラウザーで下記のURLにアクセスする
http://localhost:3000終わり!
- 投稿日:2020-12-12T16:41:12+09:00
docker composeで指定する要素メモ
・要素
1--version:docker-composeのバージョン
2--立ち上げるコンテナの名前
3--image:立ち上げるコンテナのイメージ
4--ports:ポート番号
5--networks:どのネットワークに接続させるか
6--volumes:どこのvolumeにつないでデータを保存するか
7--environment:環境変数・具体例
version:'3.7'
services:
nginx:
image:nginx:'バージョン数'
ports:
-8080:80
environment:・contextで、docker-compose.ymlからみてdockerfileがどこにあるのかを指定して
・build
docker fileがおいてあディレクトリや、docker fileの名称を指定していると思っておけば良い?
- 投稿日:2020-12-12T16:24:21+09:00
Unsupported config option for services service: ‘app’ エラー
はじめに
docker-compose.yml を書き換えた時にエラーが発生したので解決方法を備忘録として残す。
エラー
Unsupported config option for services service: ‘app’解決方法
docker-compose が古いらしい
最新のバージョンに変更する
最新のバージョンを見るには こちらからcurl -L “https://github.com/docker/compose/releases/download/バージョン指定/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose完了
参考記事
- 投稿日:2020-12-12T16:04:47+09:00
AWS Lambdaがコンテナイメージ対応したらしいのでLambda上でJUMAN++を動かしてみた
無計画なAdvent Calendar駆動開発は時間が足らなくてつらい。natsuumeです。
この記事はOpt Technologies AdventCalendarの12日目の記事です。
11日は@shoyaokayamaさんで「LINEThingsとM5CoreInkを使ってO2Oマーケティングを体験してみる」でした。はじめに
AWS Re:InventにてAWS Lambdaがコンテナイメージサポートという発表がありました。
しかも最大10GBまでのコンテナイメージが可能だそうです。となればとりあえず利用方法として下記のような例が思いつきます。
- AWS Lambda上で形態素解析器を動かす
- AWS Lambda上で深層学習の推論を動かす
今回は深層学習の推論エンドポイントとして使う方は時間の都合上試していませんが、こちらも後でやってみたいところです。
趣味で深層学習試しても推論エンドポイントずっと立てて公開するのは金銭的にちょっと……という感じだったので、多少実行時間かかるとしてもサーバレスで推論エンドポイント立てられるのは夢がありますね。深層学習モデルをLambdaに乗せる参考例
- AWS Lambdaがコンテナイメージをサポートしたので、Detectron2 を使って画像認識(Object Detection)を行うAPI を作る
- AWS Lambda + Docker + TensorFlowを使ってサクッと推論APIをつくる
また、Lambda上で形態素解析器等を手軽に動かせるようになれば、S3に溜まっていくテキストデータを加工・整形して蓄積するというフローも楽に作れるようになりそうです。
というわけで、今回はAWS Lambda上で形態素解析器(今回はJUMAN++)を動かすのを試していきます。
なお先にネタバレすると当初はKNPも入れる予定でしたが、KNPを入れたらdocker imageのサイズが10GBを超過したため諦めました。
全体構成
今回は最小構成でLambdaにテキストを投げたら解析結果をそのまま返すLambdaを作ります。
使用した全コードはgithubに下記公開してあります。
https://github.com/Natsuume/lambda-container-samplecdk
cdk.tsimport { DockerImageCode, DockerImageFunction } from "@aws-cdk/aws-lambda"; import * as cdk from "@aws-cdk/core"; import { Duration } from "@aws-cdk/core"; export class LambdaContainerSampleStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const lambda = new DockerImageFunction(this, "jumanpp-lambda", { code: DockerImageCode.fromImageAsset("./docker", { cmd: ["/var/task/jumanpp-lambda.jumanppHandler"], entrypoint: ["/lambda-entrypoint.sh"], }), timeout: Duration.seconds(30), }); } }DockerImageFunctionはイメージのpush先がaws-cdk/assets固定ですが、このような記述だけでローカルのdockerfileをpushしてlambda上で動かせます。
簡単。また、後述しますがタイムアウトは長めに取っておきます。
Dockerfile
詳しくは知らないのですがAmazon Linux2はCentOS系らしいです。
つまりaptが使えない。つらい。
yumでinstallできるcmakeのバージョンは2.x系ですがJUMAN++のインストールには3.0以上のcmakeが必要だったり、という関係で色々インストールしたりしています。ubuntu系ならもっと簡単にinstallできた記憶があるのでそっちベースで書いたほうが楽という可能性も無きにしもあらずですが、その辺は詳しくないので今回は公式で提供されている
public.ecr.aws/lambda/nodejs:12を使っています。FROM public.ecr.aws/lambda/nodejs:12 ENV JUMAN_VERSION 2.0.0-rc3 # ENV KNP_VERSION knp-4.20 RUN yum update -y RUN yum upgrade -y RUN yum -y groupinstall "Development Tools" RUN yum install -y wget # wget cmake RUN wget https://cmake.org/files/v3.18/cmake-3.18.0.tar.gz RUN tar -xvzf cmake-3.18.0.tar.gz RUN rm cmake-3.18.0.tar.gz # wget jumanpp RUN wget https://github.com/ku-nlp/jumanpp/releases/download/v${JUMAN_VERSION}/jumanpp-${JUMAN_VERSION}.tar.xz RUN tar xvf jumanpp-${JUMAN_VERSION}.tar.xz RUN rm jumanpp-${JUMAN_VERSION}.tar.xz # wget knp # RUN wget http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/knp/${KNP_VERSION}.tar.bz2 # RUN tar jxvf ${KNP_VERSION}.tar.bz2 # RUN rm ${KNP_VERSION}.tar.bz2 # install cmake RUN yum -y install openssl-devel RUN cd cmake-3.18.0 && \ ./bootstrap && \ make && \ make install # install juman++v2 RUN cd jumanpp-${JUMAN_VERSION} && \ mkdir build && \ cd build && \ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local && \ make && \ make install # install knp # RUN cd ${KNP_VERSION} && \ # ./configure && \ # make && \ # make install # clean RUN cd cmake-3.18.0 && \ make uninstall RUN rm -rf cmake-3.18.0 RUN yum -y groupremove "Development Tools" RUN yum remove -y wget COPY ./jumanpp-lambda.js /var/task CMD ["/var/task/jumanpp-lambda.jumanppHandler"] ENTRYPOINT ["/lambda-entrypoint.sh"] EXPOSE 8080lambda
lambda.tsimport * as childProcess from "child_process"; import * as util from "util"; exports.jumanppHandler = async (event: { content: string }) => { const out = await util .promisify(childProcess.exec)(`echo "${event.content}" | jumanpp`) .then((result) => result.stdout) .then((output) => output.split("\n")) .then((output) => output.filter((s) => s.length > 0)); return { result: out, }; };今回はLambda上でJUMAN++が動くかの確認がメインのため非常に簡素なコードで済ませています。
実際に運用する際には、
- execを使用しているので危険な入力が与えられる可能性があるのであればその対策
- JUMAN++の解析が失敗するような入力を正規化する(参考:稀によくあるKNPのはまりどころ)
などの入力に対する多少の変形が必要です。
結果
無事に入力文字列に対して解析結果を返すLambdaが完成しました。
前述のタイムアウトと関連しますが、実行時間は初回のみ多少時間がかかります。
実行回数 実行時間(ms) 1回目 11547 2回目 395 2回目以降はよろしくやってくれるのか、問題ない速度で動きます。
ハマったポイント
entrypoint
cdkのDockerImageFunctionの設定でかなり時間を費やしました。
DockerImageCode.fromImageAssetが引数にとるAssetImageCodePropsのentrypointの挙動が個人的にはかなりわかりにくかったです。AssetImageCodePropsは下記のプロパティを持ちます。
buildArgs?: { [string]: string }, cmd?: string[], entrypoint?: string[], file?: string, target?: string,このentrypointについて、公式リファレンスでは
Specify or override the ENTRYPOINT on the specified Docker image or Dockerfile.
と記載されています。
(参考: https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.AssetImageCodeProps.html)entrypointがoptionalだったためDockerfile側でENTRYPOINTを指定すれば問題ないと思ったのですが、どうもcdk側でもentrypointを指定しないとdeploy時にentrypointが空になるようでした。
Dockerfileの置き場
DockerImageCode.fromImageAssetでDockerfileをプロジェクト直下においてディレクトリを./に指定するとcdkコマンドで死にます。
(参考:https://github.com/aws/aws-cdk/issues/3899)ダメなパターン.tsconst lambda = new DockerImageFunction(this, "jumanpp-lambda", { code: DockerImageCode.fromImageAsset("./", { // "./"指定は死ぬ cmd: ["/var/task/jumanpp-lambda.jumanppHandler"], entrypoint: ["/lambda-entrypoint.sh"], }), timeout: Duration.seconds(30), });今回はdockerfile用にディレクトリを掘って回避しました。
おわりに
Lambdaでコンテナイメージが動かせるようになって、容量に限りはあるもののこのように実行ファイルもLambdaで手軽に使えるようになりました。
これによって手軽にサーバレスでできることがぐっと広がったのではないかと思います。以上です。
なお、アドベントカレンダーの13日も私予定ですが、間違いなく遅刻します。
参考文献
- 投稿日:2020-12-12T15:05:50+09:00
S3互換のオブジェクトストレージMinIOを利用したローカル開発環境のサンプル
こちらはニフティグループアドベントカレンダーの13日目記事です。
昨日は @esu_eichiさんの flutter で UI をどう作るかの基礎でしたね!
僕は、ほぼバックエンドしかやってこなかったのでUIの勉強もしないとなあはじめに
みなさんはS3を利用したアプリケーションを作成する際に開発環境をどのように構築していますか?
endpointにawsのs3を指定するのは楽ですが少額とはいえお金がかかるので、ローカルほうが検証しやすいですよね。
今回の記事では、ローカルS3の開発環境のサンプルを作ってみました!サンプルでできること
pythonのコンテナからminio(s3)に対してAWS SDKでアクセスし、以下の事ができます
- バケット作成と削除
- ファイル作成と削除と内容取得
環境
- Microsoft Windows [Version 10.0.18363.1198]
- Docker version 19.03.13, build 4484c46d9d
- docker-compose version 1.27.4, build 40524192
ファイル構成
│─docker-compose.yml │─Pipfile │─python.Dockerfile └─sample └─create_bucket.py └─create_file.py └─read_file.py └─delete_file.py └─delete_bucket.pyファイル内容
docker-compose.yml
各サービスの説明:
- python
- 使用しているコンテナイメージ: https://hub.docker.com/_/python
- minio
- 使用しているコンテナイメージ: https://hub.docker.com/r/minio/minio/
- ports
- minioのデフォルトポートは9000です。僕の環境だと9000番ポートは競合するため、ホストに9090を割り当てています。
- environment
- minioにアクセスする際のキーを環境変数として指定しています
- createbuckets
- 使用しているコンテナイメージ: https://hub.docker.com/r/minio/mc/
- entrypoint
- until ~~ の部分では、minioに接続できるまで待機しています。ここでは、minioにアクセスする際のキーを利用し、接続しています。
- 接続できしだい、default-bucketの作成を行っています。
docker-compose.ymlversion: "3.7" services: python: image: sample/python container_name: python build: context: ./ dockerfile: python.Dockerfile stdin_open: true volumes: - ./sample:/sample networks: default: ipv4_address: 172.21.1.2 minio: container_name: minio image: minio/minio:latest volumes: - ./minio:/export ports: - "9090:9000" environment: - MINIO_ACCESS_KEY=miniominio - MINIO_SECRET_KEY=miniominio networks: default: ipv4_address: 172.21.1.3 command: server /export createbuckets: image: minio/mc depends_on: - minio entrypoint: > /bin/sh -c " until (/usr/bin/mc config host add minio http://minio:9000 miniominio miniominio) do echo '...waiting...' && sleep 1; done; /usr/bin/mc mb minio/default-bucket; /usr/bin/mc policy download minio/default-bucket; exit 0; " networks: default: ipam: driver: default config: - subnet: "172.21.1.0/24"Pipfile
[[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] boto3 = "==1.12.9" [dev-packages] [requires] python_version = "3.8"python.Dockerfile
python.DockerfileFROM python:3.8-slim # 日本時間対応 ENV TZ=Asia/Tokyo # 作業ディレクトリ ENV WORKDIR /sample # ディレクトリ作成 RUN mkdir ${WORKDIR} WORKDIR ${WORKDIR} COPY . ${WORKDIR} # Python依存ライブラリをインストール RUN pip install --upgrade pip && \ pip install pipenv && \ pipenv installcreate_bucket.py
boto3.resourceでは、minioの環境変数で決めたMINIO_ACCESS_KEY、MINIO_SECRET_KEYを指定しています。
create_bucket.pyimport boto3 # minioをendpointにする s3_resource = boto3.resource( 's3', endpoint_url='http://minio:9000', aws_access_key_id='miniominio', aws_secret_access_key='miniominio' ) # bucket名 bucket_name = "test-bucket" # bucketを作成 s3_resource.create_bucket(Bucket=bucket_name)create_file.py
create_file.pyimport boto3 # minioをendpointにする s3_resource = boto3.resource( 's3', endpoint_url='http://minio:9000', aws_access_key_id='miniominio', aws_secret_access_key='miniominio' ) # bucket名 bucket_name = "test-bucket" # file名 file_name = "test-file" # bucketにファイル作成 s3_resource.Object(bucket_name, file_name).put(Body="hogehoge")read_file.py
read_file.pyimport boto3 # minioをendpointにする s3_resource = boto3.resource( 's3', endpoint_url='http://minio:9000', aws_access_key_id='miniominio', aws_secret_access_key='miniominio' ) # bucket名 bucket_name = "test-bucket" # file名 file_name = "test-file" # ファイルの内容を読み込む file_data = s3_resource.Object(bucket_name, file_name).get()[ 'Body'].read().decode('utf-8') print("#test-fileのファイル内容の出力") print(file_data)delete_file.py
delete_file.pyimport boto3 # minioをendpointにする s3_resource = boto3.resource( 's3', endpoint_url='http://minio:9000', aws_access_key_id='miniominio', aws_secret_access_key='miniominio' ) # bucket名 bucket_name = "test-bucket" # file名 file_name = "test-file" # test-fileを削除 s3_resource.Object(bucket_name, file_name).delete()delete_bucket.py
delete_bucket.pyimport boto3 # minioをendpointにする s3_resource = boto3.resource( 's3', endpoint_url='http://minio:9000', aws_access_key_id='miniominio', aws_secret_access_key='miniominio' ) # bucket名 bucket_name = "test-bucket" # bucketを削除 s3_resource.Bucket(bucket_name).delete()動作確認
docker-compose.ymlがあるディレクトリで以下コマンドを打ちます
$ docker-compose build $ docker-compose up -dコンテナが起動したら以下を確認します。
- http://localhost:9090/minio/ にアクセス
- docker-compose.yml内で指定しているMINIO_ACCESS_KEY、MINIO_SECRET_KEYでログイン
#docker-compose.yml より抜粋 environment: - MINIO_ACCESS_KEY=miniominio - MINIO_SECRET_KEY=miniominioログインすると以下のような画面が表示されるはずです。
その際にdefault-bucketが作成されていることを確認しましょう。
これはdocker-compose.ymlのcreatebucketsで作成されたバケットになります。
画面確認ができたので、次はpythonコンテナに入り、サンプルソースを実行していきます。
pythonコンテナに入りpipenv shellをする
$ docker exec -it python bash root@35d6e218dd79:/sample# pipenv shell Creating a Pipfile for this project... Launching subshell in virtual environment... root@35d6e218dd79:/sample# . /root/.local/share/virtualenvs/sample-Q5cUdPp_/bin/activatecreate_bucket.pyを実行しminioのweb画面からtest-bucketが作成されていることを確認する
(sample) root@35d6e218dd79:/sample# python create_bucket.py (sample) root@35d6e218dd79:/sample#http://localhost:9090/minio/
にアクセスし、以下のようにtest-bucketが作成されていることを確認するcreate_file.pyを実行しminioのweb画面でtest-fileが作成されていることを確認する
(sample) root@35d6e218dd79:/sample# python create_file.py (sample) root@35d6e218dd79:/sample#http://localhost:9090/minio/test-bucket/
にアクセスし、以下のようにtest-fileが作成されていることを確認するread_file.pyを実行しtest-fileの中身を読み込めることを確認する
(sample) root@35d6e218dd79:/sample# python read_file.py #test-fileのファイル内容の出力 hogehogedelete_file.pyを実行し、minioのweb画面でtest-fileが削除されていることを確認する
(sample) root@35d6e218dd79:/sample# python delete_file.py (sample) root@35d6e218dd79:/sample#http://localhost:9090/minio/test-bucket/
にアクセスし、以下のようにtest-fileが削除されていることを確認するdelete_bucket.pyを実行し、minioのweb画面でtest-bucketが削除されていることを確認する
(sample) root@35d6e218dd79:/sample# python delete_bucket.py (sample) root@35d6e218dd79:/sample#http://localhost:9090/minio/
にアクセスし以下のようにtest-bucketが削除されていることを確認する
無事サンプルの実行ができました!
おわりに
今回はMinIOを利用したローカル開発環境のサンプルを作成しました。
qiita投稿は初めてなのでお手柔らかにお願いします(?)明日は@kanishionoriさんです~~
参考サイト
今回の記事を作成するにあたり参考にした記事になります。大変お世話になりました。
- 投稿日:2020-12-12T14:56:36+09:00
AWSにコンテナ環境を構築する
はじめに
コンテナ開発環境をAWS上に構築します。
なお、本記事は以下のUdemy講座を元にした覚書です。
米国AI開発者がゼロから教えるDocker講座準備
コンソールよりAWSのEC2インスタンスを生成
https://aws.amazon.com/jp/console/OSはUbuntuなどを選択
インスタンスが起動したらログインし、Dockerをインストール
# sshでAWSにログイン ssh -i /Users/yukokanai/work/aws/ssh/mydocker.pem ubuntu@ec2-13-230-103-136.ap-northeast-1.compute.amazonaws.com # dockerインストール sudo apt-get update sudo apt-get install docker.io # dockerグループを作ってubuntu(ユーザー)を入れる(sudoなしでdockerを使える様にする) sudo gpasswd -a ubuntu docker # 一度ログアウトしてからもう一度入り直すと使える様になる exitAWSのインスタンスにimageをアップしコンテナ起動
いくつかあります。制約などに応じて使い分けてください。
手段①Docker HubなどのレジストリにDocker imageをpullする
インスタンスがネットにつなげられない場合は使えないです。
1.Docker Hubにアカウントを作成
https://hub.docker.com/2.ローカル環境にDockerをインストール
3.ローカル環境にてimageファイルを作成
docker build -f Dockerfile . {image名(repository)}:{tagname}4.ローカル環境よりDockerHubにpush
docker push {アカウント名}/{image名(repository)}:{tagname}5.AWSにログインし、DockerHubよりpull
docker pull {アカウント名}/{image名(repository)}:{tagname}6.DLされたimageファイルよりコンテナ起動
docker run -it {imageID}手段②Dockerfileを送る
ビルドコンテキストの差異が出る可能性がある
Cloudがネットにつなげられない場合は使えない1.ローカル環境にDockerをインストール
2.ローカル環境にてDockerfileを作成
3.sftpにてAWSへファイル転送(インスタンスは起動しておく)
# sftpでAWSへログイン sftp -i /Users/yukokanai/work/aws/ssh/mydocker.pem ubuntu@ec2-13-230-103-136.ap-northeast-1.compute.amazonaws.com # 圧縮ファイルをAWSインスタンスへput put Dockerfile /home/ubuntu # ログアウト exit4.AWSにログインし、imageファイルを作成
# ビルド docker build -f Dockerfile . {image名}:{tagname} # imageファイルが作成されていることを確認 docker images5.作成されたimageファイルよりコンテナ起動
docker run -it {imageID}手段③Docker imageを圧縮して送る
他手段に比べてimageファイルはサイズが大きいので時間がかかる
1.ローカル環境にDockerをインストール
2.ローカル環境にてimageファイルを作成
docker build -f Dockerfile . {image名}:{tagname}3.imageファイルを圧縮
docker save {imageID} > myimage.tar4.sftpにてAWSへファイル転送(インスタンスは起動しておく)
# sftpでAWSへログイン sftp -i /Users/yukokanai/work/aws/ssh/mydocker.pem ubuntu@ec2-13-230-103-136.ap-northeast-1.compute.amazonaws.com # 圧縮ファイルをAWSインスタンスへput put myimage.tar /home/ubuntu # ログアウト exit5.AWSにログインし、圧縮ファイルを展開してimageファイルを作成
# 圧縮ファイルを展開 docker load < myimage.tar # imageファイルが作成されていることを確認 docker images6.作成されたimageファイルよりコンテナ起動
docker run -it {imageID}
- 投稿日:2020-12-12T14:18:23+09:00
Movable Type Serverless - LambdaコンテナでMTを動かしてみた
Movable Type Advent Calendar 2020 12日目です。
つい先日、AWS LambdaがDockerコンテナをサポートしました。
これはアツい!ということでMTを(途中まで)動かしてみた、という話です。
Movable Type Serverless
最終的にはこんなイメージでいます。
MTの静的出力という特徴を活かし、Webサーバーだけ常時起動させますが、MTは普段存在すらしておらず、編集者が使うときだけ起動します。
- 夜中や休日など編集者が使わない時間はコンピューティングコスト節約!
- 利用者が増えたらRDSやEFSの限界まで事実上無限に性能拡張!
- もし再構築を並列で実行できたら時間を圧倒的に短縮!
なにこれすごい!
とりあえずログインできるところまでやってみた
今回はRDSと連携してログインできるところまでやってみました。
- EFSとの連携以降はやってません。
- セキュリティ考慮していません。
- 日本語だと文字化けしたのでとりあえず英語で動かします。
とまあ、PoCレベルなので誰か遺志を継いでください。
手順1 RDSインスタンスを起動
RDSにMT用のMySQLデータベースインスタンスとユーザーを作成します。
一時的な実験なのでセキュリティは考慮していません! 随時読み替えて適切に設定してください。
create user 'mt_serverless'@'%' identified by '(データベースのパスワード)'; grant all on mt.* to 'mt_serverless'@'%' with grant option; flush privileges;手順2 MTのプログラム一式を展開する
ここからはRDSに接続可能な環境で作業します。
開発者ライセンスでMTを入手します。
https://www.sixapart.jp/inquiry/movabletype/developer.html
手順3 mt-config.cgi
MTを展開したディレクトリ直下に設定ファイル
mt-config.cgiを作成します。※ 日本語が文字化けしちゃったので英語UIに逃げます。
mt-config.cgiCGIPath /mt/ StaticWebPath /mt/mt-static/ StaticFilePath /app/mt-static ObjectDriver DBI::mysql Database mt DBUser mt_serverless DBPassword (データベースのパスワード) DBHost (RDSインスタンスのホスト名) EmailAddressMain (管理者メールアドレス) DefaultLanguage en ImageDriver Imager手順4 Dockerfile
ひとまずplack/PSGIで動かすため、MTを展開したディレクトリ直下にこんな
Dockerfileを作ります。個人的に慣れてるUbuntuを使っていますが、ディストリビューションはお好きにどうぞ。
DockerfileFROM ubuntu:20.04 RUN apt-get update \ && apt-get install -y perl cpanminus build-essential \ libdbi-perl libdbd-mysql-perl \ libimager-perl libxmlrpc-lite-perl \ libplack-perl libcgi-psgi-perl \ && cpanm XMLRPC::Transport::HTTP::Plack RUN cpanm AWS::Lambda RUN apt-get -y remove build-essential \ && apt-get -y clean \ && apt-get -y autoremove \ && rm -rf /var/lib/apt/lists/* /var/cache/apt/* ADD . /app WORKDIR /app CMD [ "plackup", "mt.psgi" ]ここでインストールしているナイスなモジュール
AWS::Lambdaが、Lambda - Dockerコンテナ - PSGIアプリケーションとしてのMTを繋いでくれます。https://github.com/shogo82148/p5-aws-lambda
手順5 PSGI版の動作確認
docker build -t mt-serverless . docker run -it --rm -p 5000:5000 mt-serverlessブラウザから、
http://localhost:5000/mt/mt.cgi(localhostは作業環境に合わせて)にアクセスすると、セットアップウィザードが開始されます。文字化けの問題で、
LanguageはEnglishでひとまず進めてください。データベースのセットアップができたらOKです。
コンテナサポート ≒ カスタムランタイム
AWS Lambdaのコンテナサポートは、2年前にリリースされた
カスタムランタイムのプロトコルを踏襲しています。カスタムランタイムはHTTPによりLambdaサービスと連携しますが、コンテナも同様です。なのでコンテナの情報はまだ少ないのですが、カスタムランタイムについて調べると大抵の問題は解決できます。
今回も、AWS Lambdaカスタムランタイム用のモジュール
AWS::Lambdaを大いに活用します。https://github.com/shogo82148/p5-aws-lambda
手順6 コンテナ用エントリーポイント
bootstrapMTのディレクトリ直下に
bootstrapを作成し、実行権限を付与します。boostrap#!/usr/bin/perl use strict; use AWS::Lambda::Bootstrap; use File::Basename; # Lambdaサービスから渡されそうだが… $ENV{'LAMBDA_TASK_ROOT'} = dirname(__FILE__); # Lambdaにハンドラの入力欄がないからこちらは来ないかも? # AWS::Lambda向けに固定 $ENV{'_HANDLER'} = 'mt-lambda.handler'; my $bootstrap = AWS::Lambda::Bootstrap->new; $bootstrap->handle_events;カスタムランタイムと違い、名前は
bootstrapでなくてもよいのですが慣習に沿います。chmod +x bootstrap手順7 Lambdaコンテナ用MTエントリーポイント
mt-lambda.pl次に
bootstrapから呼び出されるMTのエントリーポイントmt-lambda.plを作成します。mt-lambda.pluse strict; use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/lib" : 'lib'; use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/extlib" : 'extlib'; use MT::PSGI; use AWS::Lambda::PSGI; my $app = MT::PSGI->new()->to_app(); my $func = AWS::Lambda::PSGI->wrap($app); sub handler { my $payload = shift; return $func->($payload); } 1;このファイル名と
sub handlerの名称は、下記のようにbootstrapの記述と関連しているので変更する場合は併せて行う必要があります。$ENV{'_HANDLER'} = 'mt-lambda.handler'; # mt-lambda → mt-lambda.pl # handler → sub handler最初は
bootstrapファイル内ですべて完結させる予定でしたが、AWS::Lambdaモジュールの実装によりそれが難しかったのでbootstrapとmt-lambda.plに分かれています。手順8 ECRにプッシュ
ECR上のリポジトリにイメージをプッシュします。細かい説明は省略します。
docker tag mt-serverless (固有のID).dkr.ecr.ap-northeast-1.amazonaws.com/mt-serverless:latest docker push (固有のID).dkr.ecr.ap-northeast-1.amazonaws.com/mt-serverless:latest手順9 Lambdaを作成
コンテナイメージを元にLambda関数を作成します。
今のコンテナイメージは
plackupでPSGI版のMTを起動するので、CMDにLabmda用のエントリポイント/app/bootstrapを指定します。作成後にLambdaのメモリとタイムアウトを変更します。
適切な設定は要検討ですが、とりあえずタイムアウト3秒は短いので30秒にしました。
手順10 Elastic Load Balancerの作成
やっと終わりが見えてきました…
Application Load Balancerを作成してLambda関数を割り当てます。
- Application Load Balancer (HTTP/HTTPS) を作成します。
- リスナーは必要に応じてHTTPSを追加してください。
- サブネットはふたつ必要です。
次に証明書とセキュリティグループを選択します。
セキュリティグループは当然、ポート80と443でのインバウンド接続を許可していください。
新しいターゲットグループとして、種類=Lambda関数を選択します。
最後に作成したLambda関数を選択します。
ついにMovable Type Serverlessにアクセス
DNSの反映に少し時間がかかるようですが、ブラウザで次のURLを開くと…
http://(ロードバランサーのDNS名)/mt/mt.cgi
き…きたー! MTのログイン画面!
セットアップ時に登録したユーザーでログインすると…
ダッシュボードだー!
しかも意外と動作が軽快。
PSGIをインターフェースとして使っていますが、ライフサイクルとしてはリクエストごとにプロセスが発生するので、挙動としてはCGIに近いはずです。もしかしたらLambdaサービスはPSGI的にプロセスがリクエスト間で使い回しているかもですが。
でもコンテナを読み込むオーバーヘッドは感じられず、実用性も期待できます。
続きを期待します
他の動作確認はしていません。そもそもEFSなどでファイルシステムを永続化しないとサイトも公開できません。
でも使った分だけ課金、並列爆速再構築など、期待が膨らみますね。
あなたがここまで読んだということは、私はすでに力尽きているだろう。ここから先のチャレンジは、あなたに道を譲ろうと思う。検討を祈る!
- 投稿日:2020-12-12T11:41:49+09:00
RaspberryPI4をサーバーにして遊び倒す。その1
この記事は Voicy Advent Calendar 2020 の 11日目の記事です。
前日は @yamagenii さんの 一瞬で作るストリームデータ収集基盤でした。明日は, @y_katsumura さんの 採用から組織開発は始まっている 〜エントリーマネジメントの重要性〜 です。はじめに
とりあえず買ったはいいがどうやって使うか迷いがちなRaspberry。
Raspberry Pi4は1GbEをフルスピードで扱えたり、USB3.0に対応するなどIO周りが強化されていて省電力なファイルサーバーとして使えそうな構成になっています。最近のアップデートは、64bitOSでUSBBootにも対応しているので、SSBから起動することによって、SDカードの書き込み最大回数をきにすることなく、またSSD化でディスクアクセス速度の向上もできるので、大分実用的に運用できるようになってきてるように思います。
ということで、なにを作ればよいかわからない人は、とりあえずサーバーにしてあそんでみるのはどうでしょうか。実用的だし、学習にもぴったりです。
この記事では、RaspberryPi4をNAS、クラウドストレージ、ストリーミングサーバーとして活用するところまで書いていきます。
書いているうちに長くなってきたので、2つに分けます。必要なもの
- Raspberry Pi4
- Boot用のSSD (容量お好みで。うちは32GB使っています)
- USB接続のSSDケースか、SATA-USB 変換ケーブル
- データ用のHDD/SSD
- USB3.0対応のHDD/SSDのケース
Raspberry Piのセットアップ
軽量化の為にデスクトップ機能は省きます。
Raspberry Pi OS Lite 64bit版をダウンロードして、EtcherでSSDにコピーしましょう。WiFi設定とsshの有効化
コピーしたSSDのbootにWiFi設定とSSHの有効化をします。
有線でつないでいる場合には、WiFi設定は飛ばしてかまいません。SSHの設定は、bootにsshのファイルを作成するだけで有効になります
$touch boot/sshWiFi設定は/bootにwpa_supplicant.confファイルを作成します。
$vi boot/wpa_supplicant.confg ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 country=JP network={ ssid="<アクセスポイントのSSID>" psk="<パスワード>" }起動して初期設定とアップデート
起動の際に、SDカードがない場合は、USBを読みにいくので、SSDをUSBにつなげて起動して、必要な初期設定を実行します。
ここでアップデートもして、一度再起動します。sudo apt update sudo apt dist-upgrade sudo rebootOpenmediavalut5をインストール
piユーザーで行ってください。
インストールに時間がかかるのでインストールされるまで待ちます。
ドキュメントによると30分かかることもあるらしいですが、そんなにはかからなかった気がします。wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bashインストールが終わったら、もう一度再起動します。
sudo reboot再起動から復帰したあと、今までのインストール作業がうまくいっていれば、ブラウザからのアクセスでログインできます。
IPアドレスが判明してる場合にはそのIPアドレスから、そうでなければ「ホスト名.local」からアクセスできるはずです。
デフォルトのホスト名だと下記になります。http://raspberrypi.localブラウザからアクセスしたらログイン画面がでるので、初期ユーザー名と初期パスワードでログインします。
- 初期ユーザー名:admin
- 初期パスワード:openmediavaultこんな画面がでたら成功です
NASの設定
左側のペインの項目から設定していきますが、ペインの項目すべてを設定しなくても、NASとして動作させられます。
最低限として以下の項目を設定します。
- 基本設定としてシステムのすべて
- ストレージのディスク、SMART、ファイルシステム
- アクセス権の管理のユーザー、共有フォルダ
- サービスのSMB/CIFS
順々に設定していきます。システム
一般設定
システム→一般設定→Web管理者パスワード
からログインしたadminのパスワードを変更します。新しいパスワードを入れて保存、適用します。
日付と時刻
タイムゾーンのプルダウンから、自分の環境に合わせて選択します。
ネットワーク
ネットワークでは一般とインターフェースのタブから設定を変更します。
インターフェースでは、自分のネットワーク環境に合わせてネットワーク接続の設定をしていきます。
モニタリング
システム→モニタリングから設定します。
モニタリングは有効(緑色)にするだけです。
SMARTの設定を有効にするのに必要です。ストレージ
ディスク
外付けのHDDなどを制御します。
「編集」では、電源管理などのオプションが選べます。
「ワイプ」では、ストレージの内容を消去できます。新しいHDDをフォーマットしたりするのに使用します。S.M.A.R.T
設定タブで有効にするだけです。
その後、デバイスタブでHDDを選択して編集と押すと、有効化できます。
設定の際は、一台づつ、保存→適用してください。ファイルシステム
Linux系では標準になっているとおり、外付けのストレージはまずマウントをしないと使えません。
「デバイス」の項目にある「/dev/sda1, /dev/sdb1」などがストレージです。
「利用可能」の項目に「n/a」「マウント済み」に「いいえ」と表示してあれば、つながっていない状態です。
デバイスを選択して、マウントボタンを押してマウントします。マウントできないとエラーがでる場合には
- フォーマット形式が異なる
- 別のシステムから移行したストレージ
- 未フォーマット
などの場合が挙げられます。
一度ストレージの中身を真っ新にする必要があるので、ディスク項目のワイプでストレージの中身を削除することで、ここで利用可能になります。
ワイプする際のポイントとしては、接続するデータ用のストレージのフォーマットはext4にしてください。
ntfs、exfat等、他のファイルシステムでも一応は機能しますが、いまのところ細かい不具合やバグなんかで動作が不安定です。
設定する際は、1台づつ保存→適用するようにしてください。マウントできると以下のように、「利用可能」の項目に「ファイルサイズ」、「マウント済み」に「はい」と表示されるようになります。
ストレージをマウントしただけでは、NASとしては利用できないので、後ほど、共有フォルダの設定をする必要があります。
アクセス権の管理
samba上でネットワークドライブとして認識させるために、
- ユーザーの作成
- 共有フォルダの指定
- sambaで共有する設定
上記の3つを設定していきます。
ユーザー
ユーザーにはRaspberry Pi OSのデフォルトユーザーのpiがすでにいますが、ネットワークから参照するのに使う専用のユーザーを作成します。
アクセス権の管理→ユーザーから追加していきます。
名前とパスワード、グループを設定してください。グループはとりあえずusersの指定があれば大丈夫です。
共有フォルダ
後ほど、sambaの設定で、sambaで共有するフォルダを選択しないといけません。
そのために、共有するフォルダを作成する必要があります。
アクセス権の管理→共有フォルダから設定していきます。デバイスのプルダウンメニューに、さきほどマウントしたストレージがでてくるので、デバイスを選択して、名前とパスを設定します。
ストレージ全体を共有したい場合は、パスは「/」のみで大丈夫です。サービス
サービスにはFTP,NFS,RSYNC,SMB/CIFS,SSHといろいろと設定したい項目がありますが、とりあえずNASとして活用するにはSambaの設定だけあれば大丈夫です。
SMB/CIFS
まずは、sambaサービスを有効にします。
次に、共有タブでSambaで共有するフォルダを選択します。
追加ボタンで出てきた項目のうち、さきほど設定した共有フォルダを指定します。
下にスクロールすると、その他、読み込み設定やパーミッションの設定もできるので任意に指定してください。単に共有するだけであれば、デフォルトのままで大丈夫です。
共有フォルダが追加されると、下記のようにリストにでてきます。
ここまでの設定が正しく反映されていれば、SAMBAで接続できるようになっているはずです。
NASとしての設定は以上です。次に、クラウドストレージとストリーミングサーバーの構築に必要な環境をセットアップしていきます。
DockerとPortainerのインストール
サーバーを追加していくにあたって、OpenmediavaultではDockerとPortainer(DockerのGUI管理)をサポートしていて非常に便利なのでインストールしていきます。
OMV-ExtrasのペインのDockerのタブに移動して、プルダウンからDockerとPortainerをそれぞれインストールします。インストールが終了したら、Open Portainerのプルダウンメニューを使って、Portainerにブラウザからアクセスします。
ログインユーザー名とパスワードを設定するよう誘導されるのでそれに従い、設定していきます。
こんな画面が出たら導入成功です。あとは、基本的には、Dockerを使って、好きなサーバーをずいずい構築していけばOKです。
クラウドストレージとストリーミングサーバーの導入については、その2に続きます。
- 投稿日:2020-12-12T08:33:22+09:00
Portainerで複数ホストのコンテナを一元管理してPortainerはいいぞと言う
この記事はDocker Advent Calendar 2020の12日目の記事として書かれました。
結論
Portainerはいいぞ。
環境
- Docker CE 19.03.13
- Docker Compose 1.27.4
- Portainer 2.0.0
Portainerとは
DockerコンテナやイメージなどをGUIで管理できるツールです。
小洒落たUIとシンプルな操作性で、入門者から上級者まで幅広い層にオススメできるツールです。
公式のデモ環境があるので、一度触ってみてください。
http://demo.portainer.io/
ID:admin
PW:tryportainer
(参考:公式Githubリポジトリ)基本的な使い方
まずはPotainerを使ってみましょう。
Portainer自体がDockerイメージとして提供されているため、以下のようにコンテナを起動するだけでOKです。$ docker run \ --detach \ --publish 9000:9000 \ --publish 8000:8000 \ --name portainer \ --restart always \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume portainer_data:/data \ portainer/portainer-ce
portainer_dataは登録した情報(ログインユーザの情報など)を永続化するためのボリュームです。
http://<ホスト名>:9000にアクセスすると、以下のようにパスワードの設定を求められます。適当な値を設定してください。
続いて管理対象の環境を選択します。[Docker] を選び [Connect] を押します。
問題なければHome画面にlocalなるエンドポイントが表示されます。
localをクリックするとContainersやImages等のリンクが表示されます。一旦Containersを確認すると、以下のようにPortainerのコンテナが正常に動作している様子を確認できます。
コンテナを追加すると自動的にPortainerの管理対象に入ります。適当にnginxを立ち上げましょう。$ docker run -dit -p 8080:80 --name nginx nginx特にエラーが出なければ、コンテナ一覧にnginxがあることが確認できるでしょう。
各コンテナの画面ではlogsでログ確認、inspectでコンテナの情報確認、statsでリソース使用量等の確認ができます。また、コンテナ起動時に
--interactive,--tty(-it)オプションを設定していればconsoleでコンテナ内部に対して操作を行うことができます。試しに先ほど起動したnginxに対してconsoleでアクセスします。コンテナ一覧から [nginx] -> [Console] とアクセスし、 [Connect] を押すと以下のようにコンテナ内に入れます。とてもお手軽です。
基本的な使い方を確認できたところで、一旦Portainerを削除します。$ docker stop portainer && docker rm portainerさて、ここまででPortainerで単一ホストのコンテナを管理する方法が分かりました。ただ、実際にはDockerホストは複数のノードにまたがっていることもあるでしょう。
この記事ではDocker Swarmで作成されたクラスタを単一のPortainerで管理する方法について説明します。
Docker Swarmで構築したクラスタのコンテナを一元管理する
1. Swarmの準備
名称 役割 説明 ip-172-31-36-96 MANAGER Swarmのマネージャノード ip-172-31-32-220 WORKER Swarmのワーカーノード ip-172-31-40-65 WORKER Swarmのワーカーノード manager1台、worker2台という構成です。
Dockerホストは
docker-machineで用意するもよし、実際に何らかのインスタンスを立てるもよしです。
今回はmanagerもworkerもAWSで雑にインスタンスを立ててDockerとDocker Composeを入れました。1.27.4の部分は公式ガイドを参考に適宜最新版に置き換えてください。$ sudo yum -y install docker $ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose(注意) クラスタ内の各ノード間で以下のポートにアクセスできるよう設定する必要があります。クラウドサービスでホストを立てたりすると恐らくデフォルトでは閉じているはずなので、各ノードが相互に以下のポートを利用できるよう設定します。
ポート番号 プロトコル 用途 2377 TCP クラスタ管理通信 7946 TCP ノード間通信 7946 UDP ノード間通信 4789 UDP オーバーレイネットワーク通信 ネットワークの設定が完了したら、各ホストをSwarmのメンバーにします。
- Swarmの作成@MANAGER
$ docker swarm init --advertise-addr <自身のIPアドレス><自身のIPアドレス>にはSwarmの他ノードから識別可能なIPアドレスを設定します。今回の例では172.31.36.96です。
- Workerを参加させるためのトークンを発行@MANAGER
$ docker swarm join-token worker -q
SWMTKNから始まるトークンが表示されます。 -q はトークンのみ表示するというオプションで、あってもなくてもいいです。(コピペが楽なので付けています)
- 各WorkerをSwarmに参加させる@WORKER
$ docker swarm join --token <トークン> <managerのIPアドレス><トークン>は先ほど作成した
SWMTKNから始まるものです。はSwarm作成時のmanagerの<自身のIPアドレス>と同じものを指定してください。
- 設定の確認@MANAGER Swarmを正常に設定できていれば、ノード一覧に3つのホストが表示されます。
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION v6zghq4r796dbg2ixow620um9 ip-172-31-32-220.ap-northeast-1.compute.internal Ready Active 19.03.13-ce 7gbjabs2eg0rqjhvkkdqwr4dq * ip-172-31-36-96.ap-northeast-1.compute.internal Ready Active Leader 19.03.13-ce xwl862sqjb5n2hs5z6nxmdz99 ip-172-31-40-65.ap-northeast-1.compute.internal Ready Active 19.03.13-ceこれでクラスタが完成しました。
2.Stackのデプロイ
StackはServiceの集合です。大雑把に捉えるとDocker Swarmはサーバを束ねる技術でDocker Stackはアプリケーションを束ねる技術です。
公式でPortainerのStackを構築するためのymlファイルが提供されているので、curlでダウンロードしてデプロイします。
$ curl -L https://downloads.portainer.io/portainer-agent-stack.yml -o portainer-agent-stack.yml $ docker stack deploy --compose-file=portainer-agent-stack.yml portainerデプロイが完了した後Portainerにアクセスすると、以下のように4つのコンテナが表示されます。Hostカラムから、3つの異なるホストにあるコンテナが1つのPortainerで管理できていることが分かります。
Stackとは別に各ノードでnginxを立ちあげてみましょう。$ docker run -dit -p 8080:80 --name nginx nginx
すべてのnginxがきちんと表示されます。--interactive,--ttyオプションをつけて起動したので、Consoleを利用できます。当然、Portainerが所属しているノードとは別のノードのnginxのConsoleにもアクセスできます。
これで複数ノードのコンテナを一元管理できるようになったことを確認できました。今回デプロイしたStackの内容を見てみましょう。
portainer-agent-stack.ymlversion: '3.2' services: agent: image: portainer/agent volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes networks: - agent_network deploy: mode: global placement: constraints: [node.platform.os == linux] portainer: image: portainer/portainer-ce command: -H tcp://tasks.agent:9001 --tlsskipverify ports: - "9000:9000" - "8000:8000" volumes: - portainer_data:/data networks: - agent_network deploy: mode: replicated replicas: 1 placement: constraints: [node.role == manager] networks: agent_network: driver: overlay attachable: true volumes: portainer_data:2つのサービス
portainerとagentを確認できます。portainerはGUIアプリケーションそのものです。agentは自ノードとPortainerの橋渡し役を担っています。
注目するべきはagentで定義されているmode: globalでしょう。これはクラスタの各ノードに該当サービスをデプロイするという指定です。各ノードにagentがいるおかげで、クラスタ内の全ノードのコンテナの情報を管理できるようになっています。
networksは両サービスが利用するネットワークを、volumesはPortainerのデータを永続化するボリュームを定義しています。どちらもデプロイ時になければ勝手に作成されます。3. Stackの更新
ここまでで複数ホストのコンテナの一元管理を実現できました。
補足としてnginxをStackに組み込んでデプロイした時の挙動を紹介します。
一旦各ノードのnginxコンテナは削除し、サービスにnginxを突っ込んで再度デプロイします。portainer-agent-stack.ymlversion: '3.2' services: agent: image: portainer/agent volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes networks: - agent_network deploy: mode: global placement: constraints: [node.platform.os == linux] portainer: image: portainer/portainer-ce command: -H tcp://tasks.agent:9001 --tlsskipverify ports: - "9000:9000" - "8000:8000" volumes: - portainer_data:/data networks: - agent_network deploy: mode: replicated replicas: 1 placement: constraints: [node.role == manager] web: image: nginx tty: true ports: - "80:80" networks: - agent_network deploy: mode: replicated replicas: 3 networks: agent_network: driver: overlay attachable: true volumes: portainer_data:$ docker stack deploy --compose-file=portainer-agent-stack.yml portainerPortainerを確認すると、きちんとサービス
webがStackに組み込まれた状態でデプロイされていることが分かります。
余談
Portainerはシンプルかつ高機能で、色々なことができます。いくつか「おー」と思ったものを紹介します。
おわりに
色々と機能を紹介したものの、正直に言ってローカルホストのコンテナの管理機能だけでも相当にパワフルです。
特にConsole機能は頻繁に使います。CUIで操作していると「あれ、今ホストだっけゲストだっけ?」となることが度々あるので。。。バージョン2.0からKubernetesに対応したらしいのでそちらも今後触ってみたいですね。
Kubernetes何もわからないので完全に理解したらまた関連記事を書こうと思います。Portainerはいいぞ。
参考
- portainer/portainer
Portainerのリポジトリです。- Portainer Deployment
本記事は"Inside a Swarm cluster"の内容を大いに参考にしました。- Docker Swarm 導入チュートリアル
Docker Swarmによるクラスタ構築の基礎です。
- 投稿日:2020-12-12T05:17:24+09:00
Docker3.0.0をアップデートしたら、なんか起動しなくなった件
どうも、三町哲平です!
Docker Desktop Community 3.0.0という
Dockerの最新バージョンが2020-12-10に出ましたね!Docker Desktopでは、最新バージョンが出るたびにアップデート通知がきますので、私も基本的に通知が来たらアップデートをしていました。
よくインターネットの書き込みなんかに○○のアプリをアップデートしたら不具合が起きたのでダウングレードしました。なんていうのを見る機会がありますが、私は今までその経験をしたことがなく、半ば都市伝説の様な半信半疑の感覚であり、他人ごとの様に感じていましたが、本日Docker Desktop Community 3.0.0で不具合が発生したので大慌てです。
エラー画面Cannot start service ec-cube: Mounts denied ERROR: Encountered errors while bringing up the project.今まで通り、 $ docker-compose up でRailsの開発環境を立ち上げようとした所上記の様なエラーが発生して、使えたはずのdocker-composeの機能が使えなくなっていました...(汗)
ちなみに上記のエラー画面は、Docker For Macを3.0.0にアップデートしたらec-cube(コンテナ)起動しなくなった - Qiitaの記事の引用をさせていただいております。当時は、焦っていてエラー内容をスクショ等で控える余裕がなかったのですね。
まずは、正解から
どうも正解は、2つあり
1つ目が.
⇒その①3.0.0を使う場合
Docker Preference(設定) > Experimental Features > Use gRPC Fuse for file sharing をオフる(デフォルトではONになっています)だそうです。
※ちなみにこの引用も下記の記事の引用です。そしてこの記事のほとんどが下記記事の引用になります。
Docker For Macを3.0.0にアップデートしたらec-cube(コンテナ)起動しなくなった - Qiita2つ目が.
=> その②2.5.系にダウングレードする
です。
ちなみに私は、解決策がわからなかったので、②2.5.系にダウングレードするを実行しました。
ダウングレードには、一度Docker Desktopをアンインストールした後に、
macユーザーだと、
Docker for Mac release notes | Docker DocumentationWindowsユーザーだと、
Docker for Windows release notes | Docker Documentationから過去のバージョンを遡ってダウンロード→インストールまでできます。
まとめ
記事の構成まで、引用元のDocker For Macを3.0.0にアップデートしたらec-cube(コンテナ)起動しなくなった - Qiitaに似てしまいましたが、
- 作業優先でろくにメジャーバージョンアップデートであることを確認しなかったのは私のミスです..
- インストールするタイミングでコンテナSTOPしていなかったのが原因かもしれないです..
と@mksm_wrk さんは書いていらっしゃいますが、この状況が私と全く同じです。
私もアップデートの通知が来た時にバージョンを一切気にせずアップデートしましたし、インストールする際にコンテナは、起動中で作業をバリバリしておりました。
しかし、ここで気にするべき点は、私は②2.5.系にダウングレードするを選択して、@mksm_wrk さんが①3.0.0を使う場合を選択できた理由が何なのかということです。
それは、
今回も世界の知見にすくわれました、ありがとう?
と@mksm_wrk さんが書いている様に英語のサイトを参考にされているということです。
いわば、日本語ではない一次情報を取りに行っているといるいうのが私との明確な差として現れてしましました。
引用のさらに大元の記事:
Unable to mount protected Mac paths after upgrade to Docker 3.0.0 · Issue #5115 · docker/for-macこれからは、翻訳機能を使いながらでも英語の記事を毛嫌いせずに読んでいかないといけなと素直に思いました。
3.0.1が出た!
なんと翌日の2020-12-11には、Docker Desktop Community 3.0.1が出ました。
特定のディレクトリがコンテナにマウントできない問題を修正しました。docker / for-mac#5115を修正と書いているのでこれが今回の件の事なのでしょう。
因みに私のDockerのバージョンは、
2.5.1→3.0.0(今回のエラー発生)→2.5.0(別のエラー発生)→3.0.1(2.5.0の時と同じエラーの為、一から環境構築中)
となっております。話は、脱線しましたが、2.5.系にダウングレードする事で今回の3.0.0でのエラーに関しては間違いなく解決されています。2.5.0(別のエラー発生)に関しては、機会があれば記事にしますが、たぶん正攻法の様なやり方をしていないので、日記みたいにな記事になりそうで、書くかどうか迷っています。
あと、更にもう一つ脱線として、
3.0.1が更新された時日付は、12-12なのに、Dockerの公式サイトでは。2020-12-11となっていてなんでだろうと思っていましたが、多分下記の様な理由かなと思います。
日本はアメリカより半日以上早いと覚えておきましょう。
では、また。
- 投稿日:2020-12-12T01:28:59+09:00
Docker Desktop Mac 3.0.0 にアップデートで起動しなくなって、mysqlが動かない時の対応
前回の記事「Docker Desktop Mac 3.0.0 にアップデートしたら、起動しなくなった時の対応」の続きです。
mysqlが永久起動失敗ループに・・・現象
下記のようなログを出力しながら、mysqlが起動→失敗→再起動を繰り返しています。
mysql | 2020-12-11 14:28:26+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql' mysql | 2020-12-11 14:28:26+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.21-1debian10 started. mysql | 2020-12-11T14:28:26.491369Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.21) starting as process 1 mysql | 2020-12-11T14:28:26.508161Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started. mysql | 2020-12-11T14:28:27.034000Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended. mysql | 2020-12-11T14:28:27.040556Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('0') and data dictionary ('2'). mysql | 2020-12-11T14:28:27.040839Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed. mysql | 2020-12-11T14:28:27.041084Z 0 [ERROR] [MY-010119] [Server] Aborting mysql | 2020-12-11T14:28:27.601939Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.21) MySQL Community Server - GPL.stack overflow に同様の現象を発見
Mysql not starting in a docker container on MacOS after docker update
mysqlのデータディレクトリをホストのvolumesに指定していると、この状況になるのでしょうか。
2.3 から 2.4 にUpdateしたときに発生していた模様です。
今回現象が出ている環境は2.5で新規作成した環境ですから、初めて出くわしたのですね・・・
(埋蔵している過去のプロジェクトを復活することになった時、これが発生するのか・・・)対応方法
stack overflowの記事の1つ目の回答の方法はダメでした。
2つ目の方法でやってみます。1.Docker Desktop をダウングレード
1) ver. 3.0.0 をUninstall
Docker Desktop > 設定 > 右上の虫っぽいマーク > Uninstall
2) ver. 2.5.0.0 をインストール
Docker for Mac release notesの 2.5.0.0をダウンロードして、インストール。
※2.5.0.1のDownloadリンクのものは「最新版dmg」へのリンクなので、3.0.0でした・・・直しておいてほしいですね;2.User gRPC FUSE for file sharing を オン
Dockerを起動して、バージョンが3.0.0でないことを確認し、
メニュー Docker Desktop > 設定 > Experimental Features の
User gRPC FUSE for file sharing を オン になっていることを確認3.docker-compose up
無事、起動しました!
(って、このまま3.0.0にアップデートせずに使えば良いのでは・・・と悪魔が囁いたのですが、本記事と前回記事の意味がなくなりますので、頑張ってみようと思います。)4.DBダンプ
どんな手段でも良いので、mysqlのDBダンプをとりましょう
5.docker-compose stop
止めます
6.mysqlのデータディレクトリを削除
mysqlコンテナ起動時に再作成してくれるそうです。
※僕は、念の為、renameにしましたが^^7.Docker Desktop 3.0.0 にアップグレード
Docker Desktop > Check for Updates... が手っ取り早いですね。
8.Docker Desktop 起動
アップデート後にStartingのまま起動しない場合は、Docker Desktop > 設定 > 右上の虫っぽいマーク > Uninstall をした後、 ver. 3.0.0をダウンロードして再インストールしてみてください。
9.User gRPC FUSE for file sharing を オフ に設定
メニュー Docker Desktop > 設定 > Experimental Features の
User gRPC FUSE for file sharing を オフ に再度設定します10.docker-compose up
無事、起動しましたか?
11.DBダンプからデータ復旧
どんな手段でも良いので、4のダンプでデータを復旧しましょう
今後は・・・
Volumeはコンテナのを使うことにします。
いま思えば、なぜホストのVolumeを割り当てていたのだろうか・・・
- 投稿日:2020-12-12T01:28:59+09:00
Docker Desktop Mac 3.0.0 にアップデートで起動しなくなって対応した後、mysqlが動かない時の対応
前回の記事「Docker Desktop Mac 3.0.0 にアップデートしたら、起動しなくなった時の対応」の続きです。
mysqlが永久起動失敗ループに・・・現象
下記のようなログを出力しながら、mysqlが起動→失敗→再起動を繰り返しています。
mysql | 2020-12-11 14:28:26+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql' mysql | 2020-12-11 14:28:26+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.21-1debian10 started. mysql | 2020-12-11T14:28:26.491369Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.21) starting as process 1 mysql | 2020-12-11T14:28:26.508161Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started. mysql | 2020-12-11T14:28:27.034000Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended. mysql | 2020-12-11T14:28:27.040556Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('0') and data dictionary ('2'). mysql | 2020-12-11T14:28:27.040839Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed. mysql | 2020-12-11T14:28:27.041084Z 0 [ERROR] [MY-010119] [Server] Aborting mysql | 2020-12-11T14:28:27.601939Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.21) MySQL Community Server - GPL.stack overflow に同様の現象を発見
Mysql not starting in a docker container on MacOS after docker update
mysqlのデータディレクトリをホストのvolumesに指定していると、この状況になるのでしょうか。
2.3 から 2.4 にUpdateしたときに発生していた模様です。
今回現象が出ている環境は2.5で新規作成した環境ですから、初めて出くわしたのですね・・・
(埋蔵している過去のプロジェクトを復活することになった時、これが発生するのか・・・)対応方法
stack overflowの記事の1つ目の回答の方法はダメでした。
2つ目の方法でやってみます。
要するに、Dockerのバージョン戻して、データ救出セヨ!です^^1.Docker Desktop をダウングレード
1) ver. 3.0.0 をUninstall
Docker Desktop > 設定 > 右上の虫っぽいマーク > Uninstall
2) ver. 2.5.0.0 をインストール
Docker for Mac release notesの 2.5.0.0をダウンロードして、インストール。
※2.5.0.1のDownloadリンクのものは「最新版dmg」へのリンクなので、3.0.0でした・・・直しておいてほしいですね;2.User gRPC FUSE for file sharing を オン
Dockerを起動して、バージョンが3.0.0でないことを確認し、
メニュー Docker Desktop > 設定 > Experimental Features の
User gRPC FUSE for file sharing を オン になっていることを確認3.docker-compose up
無事、起動しました!
(って、このまま3.0.0にアップデートせずに使えば良いのでは・・・と悪魔が囁いたのですが、本記事と前回記事の意味がなくなりますので、頑張ってみようと思います。)4.DBダンプ
どんな手段でも良いので、mysqlのDBダンプをとりましょう
5.docker-compose stop
止めます
6.mysqlのデータディレクトリを削除
mysqlコンテナ起動時に再作成してくれるそうです。
※僕は、念の為、renameにしましたが^^7.Docker Desktop 3.0.0 にアップグレード
Docker Desktop > Check for Updates... が手っ取り早いですね。
8.Docker Desktop 起動
アップデート後にStartingのまま起動しない場合は、Docker Desktop > 設定 > 右上の虫っぽいマーク > Uninstall をした後、 ver. 3.0.0をダウンロードして再インストールしてみてください。
9.User gRPC FUSE for file sharing を オフ に設定
メニュー Docker Desktop > 設定 > Experimental Features の
User gRPC FUSE for file sharing を オフ に再度設定します10.docker-compose up
無事、起動しましたか?
11.DBダンプからデータ復旧
どんな手段でも良いので、4のダンプでデータを復旧しましょう
今後は・・・
Volumeはコンテナのを使うことにします。
いま思えば、なぜホストのVolumeを割り当てていたのだろうか・・・
追記:
いま思えば、なぜホストのVolumeを割り当てていたのだろうか・・・
これ、Laradockの標準がこうなっていたから、オリジナルでdocker-compose.ymlを書くときに参考にしたのでした。
全世界のMacでLaradock使いの方々が阿鼻叫喚ってことですか!?個人的に他にも該当プロジェクトが多数あります・・・
これはやはり2.5に戻s...うぅん、なんでもないです。
- 投稿日:2020-12-12T00:37:20+09:00
Dockerって何よ
初めに
実験的にrailsアプリにDockerを導入してみましたが、根本的な理解がまだまだなので、そもそもDockerが何者なのか自分用メモとして残しておきます。
Dockerって?
Dockerは、コンテナ仮想化を用いてアプリケーションを開発・配置・実行するためのオープンソースソフトウェアあるいはオープンプラットフォームである。 Dockerはコンテナ仮想化を用いたOSレベルの仮想化によりアプリケーションを開発・実行環境から隔離し、アプリケーションの素早い提供を可能にする。 (wikipedia引用)
つまり仮想環境をPC上に作って、そこでアプリを動かせるよってことですね。
何が良いのか?
Dockerを使うメリットは以下の通りです。
1.実行環境の立ち上がりが早い
従来のホスト型仮想化では仮想ハードウェア上でOSを動かすために、ネイティブ環境と比べて動作が遅くなりがちでした。一方でコンテナ型仮想化(Docker)では起動しているコンテナで動かすので軽量です。(ゲストOSが不要)
2.Dockerfileの共有で違うPCに同じ環境を作成できる
一度Dockerfileを書いてしまえば、他人と共有することで簡単に同じ環境を整えることが出来ます。新規のメンバー参入時に即座に同じ環境が構築できるのは便利ですね。
3.環境の移動が手軽
開発環境では問題なく動作していたのに、本番環境ではちょっとした環境差分で動作しないことがあります。しかし、開発からDockerを使用することで、開発環境と本番環境の差異を吸収してくれます。つまり、アプリの再現性を高めることが可能になるということです。
試しに使ってみる
公式サイトからお使いのOSに合ったDocker Desktopをインストールします。
インストール完了後に一応バージョン確認をします。$ docker -v Docker version 19.03.13, build 4484c46d9d無事にインストール出来ていますね。
Dockerの動作確認用のコンテナとして、hello-worldコンテナがあります。docker runコマンドでイメージが取得できますので、試しにやってみます。
$ docker run hello-world 0e03bdcc26d7: Pull complete Digest: sha256:1a523af650137b8accdaed439c17d684df61ee4d74feac151b5b337bd29e7eec Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/hello-worldコンテナはあくまで動作確認なので、ターミナル上に文字が表示されるだけです。
コマンドを実行した時、裏では以下のようなことが起きています。1.Dockerクライアント(コマンド)でコンテナを要求する ↓ 2.Dockerデーモンがネットを経由してコマンドで指定されたイメージを探す ↓ 3.Dockerhubに該当するイメージが有ったらデーモンに返す ↓ 4.Dockerデーモンはクライアントに実行結果を送る尚、PC上に既にイメージがある場合は2~4は省略されます。
また、docker runは一連のコマンドを一まとめにした便利なコマンドです。
docker run = docker pull(イメージ取得) + create(コンテナ作成) + start(コンテナ起動)次に先程取得したhello-worldイメージを確認してみます。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest bf756fb1ae65 11 months ago 13.3kBhello-worldイメージが入っています。次にコンテナの方も見ていきますが、hello-worldコンテナは文字を出力したら勝手に停止するので、オプションで停止中のコンテナも見れるようにします。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 31d04b2e2868 hello-world "/hello" 14 minutes ago Exited (0) 14 minutes ago determined_mahavira最後にイメージとコンテナを削除します。
$ docker rm 31d04b2e2868(コンテナID) 31d04b2e2868 $ docker rmi hello-world(イメージ名) Untagged: hello-world:latest Untagged: hello-world@sha256:1a523af650137b8accdaed439c17d684df61ee4d74feac151b5b337bd29e7eec Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b Deleted: sha256:9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63無事に削除が完了しました。次回はより実践的な使用例に入っていきたいと思います。
参考にさせていただいた記事
- 投稿日:2020-12-12T00:13:08+09:00
VisualStudio CodeからMongoDBにつなげてみよう!
はじめに
この記事は、Visual Studio Code Advent Calendar 2020 の11日目の記事になります。
今回は、表題の通りMongoDB for VS Codeを使ってMongoDBに接続してみるというお話です。(※VisualStudio Code は、以下VSCodeと記載します)ところでなぜMongoDB?
ただいま個人学習として、MondoDB公式が提供している、MongoDB Universityというオンライン学習コースをコツコツ進めています。12
MongoDBのクライアントとしては、MongoDB Compassという非常に優れたツールがあります。ただ、コーディングしながらであれば、データの簡単な確認はエディタ内で済ませたい...。
また、コースが進むにつれ、APIのみでの操作でなく、MongoDBのプロセスや運用面のトピックも出てきたので、もう少しデータファイルなども見える方が良い。幸い、Dockerの公式イメージもあるので、ローカル開発環境での起動にはDockerが使えます。このあたりを踏まえて、「全部VSCode内で完結するかしら?」と思ってやってみた顛末となります。
まずはMongoDBのDockerイメージを使おう!
実のところ、MongoDB Atlasというクラウドのサービスを使えば、無償枠でもサービスとしてはMondoDBの操作が可能なので、MongoDB Extensionを試すのにはローカルでDockerのMongoDBを起動する必要はありません。
ただし、上記の通り、プロセスやデータファイルの管理の仕方も合わせて確認したいので、Dockerで起動してみることにします。
公式のイメージから起動するよ!
イメージは、こちらを使います。
VSCodeのDocker Extensionも非常に便利で日々進化していて、これがないとわたしはお仕事ができません...。3
わたしの環境はMacですので、DockerのホストとしてはDocker for Macを利用します。# まずはイメージを引っ張ってきます docker pull mongoイメージを取得後、VSCodeのDocker Extensionを使うと、Dockerイメージの一覧や起動中のコンテナが表示できます。
MondoDBのイメージは、そのままVSCodeから右クリックで起動ができます。コンテナが立ち上がると、上部にMongoDBのコンテナが表示されます。
ここからさらに右クリックで起動中のコンテナ内にアクセスしたり、ログを確認することができます。
コンテナ内のファイルシステムも、VSCodeから表示できるようになっています。コンテナ内に入ってMongo Shellを利用してみよう!
VSCodeのコンテナの表示から、右クリックでコンテナにアタッチします。(Attach Shellで、実際は docker execコマンドが走ります)
MondoDBの公式イメージは、シェルにアクセスできるので、コンテナ内でpsコマンドでMondoDBのプロセスが上がっていることを確認してみました。
内部には、もちろんMongoDB Shell (データベースにアクセスするためのCUIのクライアント)が入っているので、単純に
mongoコマンドを打つだけで、操作が可能になります。ちょっと長いですが、コンテナ内での結果を貼ってみます。
# mongoコマンドで起動(内部からでパスワード無し) root@b0c9ee280d35:/# mongo MongoDB shell version v4.4.2 connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("fec4ef7e-b4b4-4b55-937c-1ccf82510de9") } MongoDB server version: 4.4.2 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see https://docs.mongodb.com/ ...[一部略]... --- > show databases admin 0.000GB config 0.000GB local 0.000GB test 0.000GB > use test switched to db test > show collections sales > db.sales.findOne() { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") }データベースの一覧表示と、test DBへの切り替えができました。
また、デフォルトで /data/db 以下にあるデータファイルも見てみます。
root@b0c9ee280d35:/data/db# pwd /data/db root@b0c9ee280d35:/data/db# ls -w 1 WiredTiger WiredTiger.lock WiredTiger.turtle WiredTiger.wt WiredTigerHS.wt _mdb_catalog.wt collection-0--359143437334718796.wt collection-13--359143437334718796.wt collection-2--359143437334718796.wt collection-4--359143437334718796.wt diagnostic.data index-1--359143437334718796.wt index-14--359143437334718796.wt index-3--359143437334718796.wt index-5--359143437334718796.wt index-6--359143437334718796.wt journal mongod.lock sizeStorer.wt storage.bsonMongoDBのストレージエンジンはWiredTigerを使っているので、
WiredTiger.*なファイルがあるのが確認できました。
コレクション(データベースに相当)するファイル、インデックスファイルは、拡張子が.wtになっています。Docker Extensionは便利ですね!
MongoDB for VS Codeを使ってみよう!
長くなりましたが、ここからが本題です。
まずは拡張機能のメニューから、MongoDBと検索し、追加してみましょう。
20201211時点では、プレビュー版となっていますが、それでもだいぶいろんなことができます!20201211時点での機能は、以下の通り。
- MongoDB Atlas、もしくは任意のMondoDBに接続ができる
- コレクション(テーブルに相当)の表示
- スキーマの表示
- ドキュメント(レコードに相当)の表示
- MongoDB Playgrounds という機能で、エディタ上に記載したMongoDB用のクエリを実行し、データの追加や検索、アグリゲーションの操作ができる
- MongoDB Shellの起動ができる4
- Terraformを使って、MondoDB Atlas上のデータベースの構成を管理できる
GitHub上のIssue (Feature)もたくさんあって、今後ますます楽しみです!
まずは接続をしてみよう!
Dockerで起動したMongoDBは、特に指定がなくても以下のコマンドで起動してくれるので、Mac側にポート27017がフォワードされるため、localhost:27017を介して接続できるようになります。
docker run --rm -d -p 27017:27017/tcp mongo:latest拡張機能を追加すると、葉っぱのマークが左のバーに表示されるので、そこからMongoDB操作用のパネルに切り替えができます。
接続設定を行うため、Connectionsのメニューから右クリックで Add MongoDB Connection を選ぶと、接続設定用の画面が表示されます。
単純に起動した場合は、パスワードは設定無しの状態で起動しますので、接続設定には、以下を記載してボタンを押せばOKです。5
- Hostname: localhost
- Port: 27017
※PCやご利用の環境でファイアウォールやセキュリティソフトがPort 27017の通信をブロックしていると、正しく接続できないのでご注意を!
うまくいくと、左側にデータベースの一覧が表示されます。
まだ管理用のものしかありません。各データベースをクリックすると、テーブルに相当するコレクションが表示されます。
次々とクリックしていくと、さらにインデックスやスキーマ、データも表示できます。MongoDB Playgroundsを使ってデータベースを作成してみよう!
おそらく何らかのデータベース用のGUIクライアントを使ったことがある方は、あとは直感的に操作がわかると思います。
さて、管理用のデータベースだけでは困るので、データベースの作成をしてみたい。
MongoDB Shellを使ってデータベース作成もできますが、この拡張機能には、MongoDB Playgrounds という機能があります。操作パネルの下の方に、Create New Playgroundsというボタンがあるのでクリックすると、MongoDB操作用のサンプルスクリプトが書かれた画面が表示されます。
この言語はMQL(MongoDB Query Language)と言われるものです。6この画面には、こんな内容が書かれています。
内容は、こんな感じ。
- 任意のデータベース(ここでは
mongodbVSCodePlaygroundDB)に接続- データベースの
salesというコレクションにデータを追加
- ちなみに、デフォルトではコレクションが存在しない場合は、勝手に作成されます
- データ登録後、find() クエリで検索を実行します
- aggregationを使って、検索&集計をします
// Select the database to use. use('mongodbVSCodePlaygroundDB'); // Insert a few documents into the sales collection. db.sales.insertMany([ { '_id' : 1, 'item' : 'abc', 'price' : 10, 'quantity' : 2, 'date' : new Date('2014-03-01T08:00:00Z') }, { '_id' : 2, 'item' : 'jkl', 'price' : 20, 'quantity' : 1, 'date' : new Date('2014-03-01T09:00:00Z') }, { '_id' : 3, 'item' : 'xyz', 'price' : 5, 'quantity' : 10, 'date' : new Date('2014-03-15T09:00:00Z') }, { '_id' : 4, 'item' : 'xyz', 'price' : 5, 'quantity' : 20, 'date' : new Date('2014-04-04T11:21:39.736Z') }, { '_id' : 5, 'item' : 'abc', 'price' : 10, 'quantity' : 10, 'date' : new Date('2014-04-04T21:23:13.331Z') }, { '_id' : 6, 'item' : 'def', 'price' : 7.5, 'quantity': 5, 'date' : new Date('2015-06-04T05:08:13Z') }, { '_id' : 7, 'item' : 'def', 'price' : 7.5, 'quantity': 10, 'date' : new Date('2015-09-10T08:43:00Z') }, { '_id' : 8, 'item' : 'abc', 'price' : 10, 'quantity' : 5, 'date' : new Date('2016-02-06T20:20:13Z') }, ]); // Run a find command to view items sold on April 4th, 2014. db.sales.find({ date: { $gte: new Date('2014-04-04'), $lt: new Date('2014-04-05') } }); // Run an aggregation to view total sales for each product in 2014. const aggregation = [ { $match: { date: { $gte: new Date('2014-01-01'), $lt: new Date('2015-01-01') } } }, { $group: { _id : '$item', totalSaleAmount: { $sum: { $multiply: [ '$price', '$quantity' ] } } } } ]; db.sales.aggregate(aggregation);この内容を、直にMongoDB Shellに貼り付けても同じことはできますが、MongoDB Playgroundsを使うと、画面上部に▶︎の実行マークが表示され、そのマークを押すと、MongoDBに対し上記の処理が実行されます。
または、実行したい箇所(行)単位を選択すると、うっすらと▶︎の実行マークが表示され、その箇所だけが実行されます。
Playgroundのパネル上の処理を実行後、MongoDBの操作パネル側からデータを確認すると、salesというデータベースが作成され、8件追加されたのがわかります。
また、選択箇所単位での実行が可能で、実行結果は別パネルに表示されます。
このPlaygroundのパネル上の内容は書き換えた上での実行が可能なので、MongoDB Shellを使わずに、複雑なクエリを投げたい場合には特に重宝すると思います。
まとめ
以上、ざっくりと機能紹介をさせていただきました。
MongoDB for VS Codeの操作パネルの下側には、ドキュメントへのリンクや、GitHub Issueへのリンク、それからMongoDB Atlas上にクラスタを作るショートカットも用意されています。
まだまだ開発途上なので、もう少し使い倒して、なにかフィードバックできたらなと思っています。
今回は合わせてDocker Extensionについても触れています。
Dockerの技術は日々進歩していて、大規模な管理の仕組みはわたしは全く追いつけていないのですが、イメージやコンテナの基本操作は、GUIの力を借りて確認しながら覚えていけます。
アプリケーション開発に取り組む方は、ぜひVSCodeと合わせて使ってみてくださいね!
MongoDBの基本を学習できるオンラインでの学習コースです。基本コースから開発者、管理者向けにコースがわかれていき、データモデリングやセキュリティ、デバッグといった範囲も扱います。 ↩
「ひとりMongoDB University」と題して学習記録を付けています。 ↩
いまや、Dockerコンテナの中に入って直にVSCodeでコンテナ内のファイルが編集できるようになっています。(https://code.visualstudio.com/docs/remote/containers) ↩
ローカルのMondoDB Shell (mongosh) を呼び出してくれます。このため、mongoshのインストールとVSCodeへのパスの追加が必要です。 ↩
実運用ではこの状態はよろしくないので、
authentication is enabledなモードで起動をしましょう...。 ↩https://developer.mongodb.com/how-to/getting-started-atlas-mongodb-query-language-mql に、このPlaygroundでMQLを利用する方法が詳細に紹介されています。(英語) ↩


















































































