- 投稿日:2020-01-15T16:05:00+09:00
Azure 上の Minecraft マルチサーバを IFTTT でいい感じに起動・終了制御する
はじめに
Azure の仮想マシンを使って、 Minecraft (Spigot) マルチサーバを立ち上げて運用しています。
参加メンバーは全員会社勤めなので、平日の日中はサーバを停止して、「平日の夜・土日の終日」の間だけ自動でサーバが立ち上がるようにしています。
今回は、サーバの開始・起動スケジュールを IFTTT の DateTime トリガーと連動して行うために、 Azure Automation を使い、更に仮想マシンの起動・終了に連動した Minecraft サーバを構築しました。
また、サーバの起動や終了は最終的に Discord に通知ようにしています。
この記事では、以下の手順で解説しています(基礎知識的な部分は省略しています)。
- 仮想マシンの構築
- VM の起動と終了に連動した Minecraft サーバを構築します
- Azure Automation で Webhook を作成する
- VM の起動と終了を行い、Discord に Webhook で通知する Runbook を構築します
- IFTTT で Webhook のトリガーを作成する
仮想マシンの構築
今回作成した VM は以下のようなスペックでした。
- SKU: Standard D2s v3 (2 vcpu 数、8 GiB メモリ)
- Region: 東日本
- Image: Ubuntu Server 18.04 LTS
D2s v3 で
¥9,166/月
ですが、平日は 6h 程しか稼働しないため、大体 300h/月 となり、現在はこの半額程度で運用しています(価格だけで見たらやっぱりちょっと高い気もする)。Spigot サーバの構築
今回は Docker を使って構築しました。
nimmis/docker-spigot を Clone してdocker-compose.yml
の値を変更するだけで終わりです。VM上にCloneする$ sudo mkdir -p /minecraft $ sudo chown -R mcserver:mcserver /minecraft $ git clone --depth=1 https://github.com/nimmis/docker-spigot /minecraftdocker-compose.ymlversion: "2" services: spigot-main: container_name: "spigot-main" build: "." ports: - 80:8123 - 25565:25565 environment: - MC_MAXMEM=8g - MC_MINMEM=1g - SPIGOT_AUTORESTART=yes - SPIGOT_VER=1.14.4 - SPIGOT_UID=1000 volumes: - "./server:/minecraft" restart: "always"これで
docker-compose up
すればspigot.jar
のビルドが走り、以降はサーバが自動で立ち上がるようになっています。終了時スクリプト
仮想マシンが停止しようとする時に、Minecraft サーバのワールドデータを
/save-all
した上で終了する必要がありますが、今回利用したイメージは、コンテナが Stop する際にそのあたりを自動でやってくれています。なので終了時スクリプトを書いてシャットダウン時にコンテナを停止するようにします。
終了時スクリプトの作成
$ sudo vim /etc/init.d/stop-mcserver.sh $ sudo chmod a+x /etc/init.d/stop-mcserver.sh $ sudo ln -s /etc/init.d/stop-mcserver.sh /etc/rc6.d/K99stop-mcserver/etc/init.d/stop-mcserver.sh#!/bin/bash cd /minecraft /usr/local/bin/docker-compose stopまた、
restart: "always"
なので次回起動時に自動的にコンテナが立ち上がって Minecraft サーバが復帰するため、これで自動起動・終了の仕組みが完成します!!!しなかった
原因が未だに分からないんですが、Azure の仮想マシンが再起動した後に何故かコンテナが自動で立ち上がりません。
ですが、SSH して
docker ps
などを叩くと 微妙なラグの後にコンテナが起動 したため、おそらく Docker daemon のプロセスが正しく起動していないのではと考えられます。起動時スクリプト
なので、起動時に Docker API を叩く無害なコマンドを実行させることで無理やり Docker daemon を起動させています。
これで、仮想マシンが再起動した後もコンテナが自動で立ち上がるようになりました。
起動時スクリプト
$ crontab -ecrontab の中身:
# m h dom mon dow command @reboot /usr/bin/docker --version > dev/null 2>&1Azure Automation で仮想マシンを起動・終了させる
Azure Automation の Runbook でこれらの内容を実装します。
- サーバを起動させる
- サーバを停止させる
- 起動・停止したら Discord の Webhook で通知する
- Automation 開始トリガーを Incoming Webhook にする
サーバを起動・停止させる
これは、 Runbook ギャラリーの人気上位にある 2つのスクリプトをインポートすれば終わりです。
ですが、インポートしてきた Runbook は Azure の仕様変更に合わせて更新されておらず、正しく起動・停止できたのにも関わらず Automation ジョブが Error で終わるようになっています。
原因は Notify VM Started/Stopped ノードの実行条件式が古いためで、これを現在の ActivityOutput のプロパティに合わせることで解決します(あと Notify Failed To Start/Stop ノードあたりのエラー内容の取得方法も古かったため直しました)。
Discord の Webhook で通知する
※ Webhook は作成済みです
以下のような感じでそれぞれの出力メッセージを IDictionary -> JSON に変換して、その内容を Webhook で Discord に通知しています。
Format message
Write-Output
ノードを使い、Discord の Webhook の仕様に合わせてコンテンツを作成。PowerShell式@{ content = $_ }ConvertTo-Json
Format message からアクティビティの出力を受け取る
Notify to webhook
Invoke-WebRequest
ノードを使い、ConvertTo-Json のアクティビティの出力をPOST
で送信。
Content-Type にapplication/json; charset=utf-8
を指定しないと日本語が文字化けする。
あとUseBasicParsing
フラグもTrue
にしないとジョブが正しく終わらなかった(はず)。開始トリガーの Incoming-Webhook を作成する
それぞれの Runbook で Webhook を作成して動くかどうか確認する。
$ curl -X POST -H "Content-Type: application/json" https://WEBHOOKこのように通知されて仮想マシンが起動・終了すれば OK(Runbook 上のメッセージを日本語に変えています)。
それぞれの Webhook URL を控えておきます。
IFTTT のトリガーを作成する
IFTTT の DateTime トリガーから Every day of the week at を選択します。
曜日と時間が選択出来るので、例えば 平日の19時に実行するようなトリガー を作成します。
次に実行するアクションで Webhook を選択し、先程の Webhook URL を設定します。
これを複数個作成し、1週間分の起動・停止スケジュールを作成すれば完成です。
ちなみに
Azure Automation 自体にもスケジュール実行機能が備わっていますが、
正直使い勝手が良くないのとスマートフォン上から編集しづらいのでIFTTT 経由でスケジュールを編集出来る方がより簡単です。完全に蛇足ですが仮に祝日判定などの機能追加をする場合も、Runbook 上で構築するよりも Discord の Bot を別途ホストして独自でスケジューリングを実装するのが良いと思います。
- 投稿日:2020-01-15T16:05:00+09:00
Azure 上の Minecraft マルチサーバを IFTTT でいい感じに制御して節約する
はじめに
Azure の仮想マシンを使って、 Minecraft (Spigot) マルチサーバを立ち上げて運用しています。
参加メンバーは全員会社勤めなので、平日の日中はサーバを停止して、「平日の夜・土日の終日」の間だけ自動でサーバが立ち上がるようにしています。
今回は、サーバの開始・起動スケジュールを IFTTT の DateTime トリガーと連動するため Azure Automation を使い、更に 仮想マシンの起動と終了に連動する Minecraft サーバ を構築しました。
最終的にはサーバの起動通知を Discord に送るようにしてメンバーが確認できるようにしています。
この記事では、以下の手順で解説しています(基礎知識的な部分は省略しています)。
- 仮想マシンの構築
- VM の起動と終了に連動した Minecraft サーバを構築します
- Azure Automation で Webhook を作成する
- VM の起動と終了を行い、Discord に Webhook で通知する Runbook を構築します
- IFTTT で Webhook のトリガーを作成する
仮想マシンの構築
今回作成した VM は以下のようなスペックでした。
- SKU: Standard D2s v3 (2 vcpu 数、8 GiB メモリ)
- Region: 東日本
- Image: Ubuntu Server 18.04 LTS
D2s v3 で
¥9,166/月
ですが、平日は 6h 程しか稼働しないため大体 300h/月 となり、月額のおよそ 1/2 程度で運用しています(価格だけ見たらやっぱりちょっと高い気もする)。Spigot サーバの構築
今回は Docker を使って構築しました。
nimmis/docker-spigot を Clone してdocker-compose.yml
の値を変更するだけで終わりです。VM上にCloneする$ sudo mkdir -p /minecraft $ sudo chown -R mcserver:mcserver /minecraft $ git clone --depth=1 https://github.com/nimmis/docker-spigot /minecraftdocker-compose.ymlversion: "2" services: spigot-main: container_name: "spigot-main" build: "." ports: - 80:8123 - 25565:25565 environment: - MC_MAXMEM=8g - MC_MINMEM=1g - SPIGOT_AUTORESTART=yes - SPIGOT_VER=1.14.4 - SPIGOT_UID=1000 volumes: - "./server:/minecraft" restart: "always"これで
docker-compose up
すればspigot.jar
のビルドが走り、以降はサーバが自動で立ち上がるようになっています。終了時スクリプト
仮想マシンが停止しようとする時に、Minecraft サーバのワールドデータを
/save-all
した上で終了する必要がありますが、今回利用したイメージは、コンテナが Stop する際にそのあたりを自動でやってくれています。なので終了時スクリプトを書いてシャットダウン時にコンテナを停止するようにします。
終了時スクリプトの作成
$ sudo vim /etc/init.d/stop-mcserver.sh $ sudo chmod a+x /etc/init.d/stop-mcserver.sh $ sudo ln -s /etc/init.d/stop-mcserver.sh /etc/rc6.d/K99stop-mcserver/etc/init.d/stop-mcserver.sh#!/bin/bash cd /minecraft /usr/local/bin/docker-compose stopまた、
restart: "always"
なので次回起動時に自動的にコンテナが立ち上がって Minecraft サーバが復帰するため、これで自動起動・終了の仕組みが完成します!!!しなかった
原因が未だに分からないんですが、Azure の仮想マシンが再起動した後に何故かコンテナが自動で立ち上がりません。
ですが、SSH して
docker ps
などを叩くと 微妙なラグの後にコンテナが起動 したため、おそらく Docker daemon のプロセスが正しく起動していないのではと考えられます。起動時スクリプト
なので、起動時に Docker API を叩く無害なコマンドを実行させることで無理やり Docker daemon を起動させています。
これで、仮想マシンが再起動した後もコンテナが自動で立ち上がるようになりました。
起動時スクリプト
$ crontab -ecrontab の中身:
# m h dom mon dow command @reboot /usr/bin/docker --version > dev/null 2>&1Azure Automation で仮想マシンを起動・終了させる
Azure Automation の Runbook でこれらの内容を実装します。
- サーバを起動させる
- サーバを停止させる
- 起動・停止したら Discord の Webhook で通知する
- Automation 開始トリガーを Incoming Webhook にする
サーバを起動・停止させる
これは、 Runbook ギャラリーの人気上位にある 2つのスクリプトをインポートすれば終わりです。
ですが、インポートしてきた Runbook は Azure の仕様変更に合わせて更新されておらず、正しく起動・停止できたのにも関わらず Automation ジョブが Error で終わるようになっています。
原因は Notify VM Started/Stopped ノードの実行条件式が古いためで、これを現在の ActivityOutput のプロパティに合わせることで解決します(あと Notify Failed To Start/Stop ノードあたりのエラー内容の取得方法も古かったため直しました)。
Discord の Webhook で通知する
※ Webhook は作成済みです
以下のような感じでそれぞれの出力メッセージを IDictionary -> JSON に変換して、その内容を Webhook で Discord に通知しています。
Format message
Write-Output
ノードを使い、Discord の Webhook の仕様に合わせてコンテンツを作成。PowerShell式@{ content = $_ }ConvertTo-Json
Format message からアクティビティの出力を受け取る
Notify to webhook
Invoke-WebRequest
ノードを使い、ConvertTo-Json のアクティビティの出力をPOST
で送信。
Content-Type にapplication/json; charset=utf-8
を指定しないと日本語が文字化けする。
あとUseBasicParsing
フラグもTrue
にしないとジョブが正しく終わらなかった(はず)。開始トリガーの Incoming-Webhook を作成する
それぞれの Runbook で Webhook を作成して動くかどうか確認する。
$ curl -X POST -H "Content-Type: application/json" https://WEBHOOKこのように通知されて仮想マシンが起動・終了すれば OK(Runbook 上のメッセージを日本語に変えています)。
それぞれの Webhook URL を控えておきます。
IFTTT のトリガーを作成する
IFTTT の DateTime トリガーから Every day of the week at を選択します。
曜日と時間が選択出来るので、例えば 平日の19時に実行するようなトリガー を作成します。
次に実行するアクションで Webhook を選択し、先程の Webhook URL を設定します。
これを複数個作成し、1週間分の起動・停止スケジュールを作成すれば完成です。
ちなみに
Azure Automation 自体にもスケジュール実行機能が備わっていますが、
正直使い勝手が良くないのとスマートフォン上から編集しづらいので IFTTT 経由でスケジュールを編集出来る方がより簡単です。完全に蛇足ですが仮に祝日判定などの機能追加をする場合も、Runbook 上で構築するよりも Discord の Bot を別途ホストして独自でスケジューリングを実装するのが良いと思います。
- 投稿日:2020-01-15T16:04:46+09:00
とりあえずのDockerfileを作成したい。
応用範囲が広いDockerfileのテンプレートを書いた。
僕はArchliluxが好きだ。つまりpacmanとaurが好きだ。archwikiとpkgbuildが好きだ。
それをそのままDockerに応用したい。そしてserverでもそのまま使いたいし、開発にも応用したい。FROM archlinux/base ARG PKG="yay" RUN curl https://www.archlinux.org/mirrorlist/\?country\=JP\&protocol\=https\&ip_version\=4\&ip_version\=6 > /tmp/mirrorlist && sed -e "s/^#//g" /tmp/mirrorlist > /etc/pacman.d/mirrorlist && yes "" | pacman -Syy git base-devel RUN useradd -m -s /bin/bash docker RUN echo 'Defaults visiblepw' >> /etc/sudoers RUN echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER docker WORKDIR /home/docker ##RUN sudo pacman -S $PKG RUN git clone https://aur.archlinux.org/$PKG.git && cd $PKG && yes "" | makepkg -si && rm -r ~/$PKG ENTRYPOINT ["bash", "-c", "echo editThisCommand."]使い方
2行目を編集するだけ!AURじゃない場合普通にpacmanでインストールできます。コメントアウト等は適当に。
ARG PKG="samba"と書けばファイルサーバーになるし、ARG PKG="dnsmasq"と書けばDNSサーバーになります。例えば
FROM archlinux/base ARG PKG="samba" RUN curl https://www.archlinux.org/mirrorlist/\?country\=JP\&protocol\=https\&ip_version\=4\&ip_version\=6 > /tmp/mirrorlist && sed -e "s/^#//g" /tmp/mirrorlist > /etc/pacman.d/mirrorlist && yes "" | pacman -Syy git base-devel RUN useradd -m -s /bin/bash docker RUN echo 'Defaults visiblepw' >> /etc/sudoers RUN echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers #USER docker #WORKDIR /home/docker RUN pacman -S $PKG ##RUN git clone https://aur.archlinux.org/$PKG.git && cd $PKG && yes "" | makepkg -si && rm -r ~/$PKG ##https://wiki.archlinux.jp/index.php/Samba を参考に RUN curl "https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD" > /etc/samba/smb.conf RUN yes "password" | pdbedit -a docker -t RUN chmod 0777 /home/docker ENTRYPOINT [ "bash", "-c", "nmbd -D && smbd -F </dev/null" ] ]
- 投稿日:2020-01-15T14:25:46+09:00
Dockerの中にPostgres+Sequelize+Express+Next.JSの構築
はじめに
この記事は、Dockerの中のExpressにSequelizeを使ってPostgresを接続する記事である。
調べても、記事ごとに構築の仕方の差が激しかったので、自分にとってやりやすいやり方を編み出し、まとめる。注意
これはメモ
基本的な解説はしない。DBとExpressのコネクションについてがメイン
Dockerについて全く理解していないので、ディレクトリ構造やDockerfileの書き方がよくないかもしれない。環境
- Docker
- Node.js
- Express
- PostgreSQL
- Next.js(APIでやり取りするのでサーバー立てて終わり)
ディレクトリ構造
product-docker-express-Dockerfile//マウント用 -next-Dockerfile//マウント用 -express //expressを直接インストール -next //Nextを直接インストール -docker-composeproduct/expressにsequelizeをインストール
npm install --save sequelize pg sequelize-cliDocker-composeでの設定
docker-composeversion: '3' services: backend: build: context: ./docker/express dockerfile: Dockerfile image: back container_name: back ports: - 3000:3000 environment: DATABASE_URL: postgres://postgres:postgres@db:5432/postgres volumes: - ./express:/src command: [sh, -c, npm install && npm start] frontend: build: context: ./docker/next dockerfile: Dockerfile image: front container_name: front ports: - 3001:3000 volumes: - ./next:/src command: [sh, -c, npm install && npm run dev] db: image: postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - "5432:5432"ここで重要なのは、DATABASE_URLである。
のちに、sequelizeのconfig.jsonにて環境変数として使用するため設定している。
postgres://postgres:postgres@db:5432/postgres
このURLは、
postgres://username:password@host:port/dbname
となっており、docker-composeで設定した通りに当てはめていく。
dbnameは、postgres-Docker Hubによると、POSTGRES_DBの記述がなければ、POSTGRES_USERの値が代わりに使用される。Sequelize
cliをインストールしたことによって、RailsのActiveRecordのように、modelやmigrationを生成することができる。
$ sequelize init //modelやmigration、configなどのフォルダーを生成。やりたいひとはやろうなテスト
$ docker-compose up -d$ docker-compose run backend npx sequelize model:create --name Test //モデルとマイグレーションファイルを生成$ docker-compose run backend npx sequelize db:migrate --env developmentまだ、エラーがでるはず...
config/config.jsonの設定
"development": { "dialect": "postgres", "use_env_variable":"DATABASE_URL" }
dialect
はDBの種類
use_env_variable
は環境変数を参照する。つまり、dockercomposeで設定したURLが参照されている。そして記事内の「やりたいひとはやろうなテスト」を行うと...
マイグレーションが反映される。まとめ
なにが正解かわからないが、他の記事などを見るとSQLスクリプトを書いていたり、自分でmodelを書いていたりしていたので調べるのが大変だった。
一番最初の環境構築でつまづいた初心者がまとめたものなので参考にならないかも。
なにかあれば...twitter@izszzz_
- 投稿日:2020-01-15T13:24:10+09:00
作業環境を改善(10年計画)
docker(19) 言語処理100本ノックをdockerで。python覚えるのに最適。
https://qiita.com/kaizen_nagoya/items/7e7eb7c543e0c18438c4作業で、PC(mac OS)3台使い、ディスプレイ3台で作業した状況を、研究環境だけではなく、量産の開発・運用へ展開するための方策を検討する。
PC 3台
Windows, Linux, macOSの3つのOSを1台づつを想定。
github/gitlab/bitbacket利用
顧客指向の土台
https://qiita.com/kaizen_nagoya/items/3ff2b93acef88e17fce8docker, docker hub(privateを含む)利用
docker(0) 資料集
https://qiita.com/kaizen_nagoya/items/45699eefd62677f69c1dvs code 利用
UML利用
xtUMLを導入する(linux編)
https://qiita.com/kaizen_nagoya/items/297097cc47a6487d9f20空間
廊下、会議室、研修室、倉庫など、電源さえあればどこでも暮らせる。
keyboard
Note PCのキーボードは、Typewriterを叩いていた身としては深さが足りない。
指が疲れてきてしまう。mouse
Note PCのパッドは、まだ慣れない。
iPad, android PADなども利用したことがあり、体がまだ馴染んでいない。
tablet用のpenは、それなりに利用経験があり、まだ馴染む。無線
通信が専門で媒体は無線のはず。資料がまだ道半ば。
無線網(Wi-Fi)空中線(antenna)(0) 記事一覧(118/300目標)
https://qiita.com/kaizen_nagoya/items/5e5464ac2b24bd4cd001
- 投稿日:2020-01-15T13:03:55+09:00
Dockerイメージを格納するため、HelmでHarborをデプロイしてみた
はじめに
これまでDockerHubの有料プランを利用してきましたが、さすがに開発用のイメージまで置く余裕はないので、Harborをデプロイして試すことにしました。今回はHelmを利用しています。
環境
- Harbor-Helmを利用してk8s環境にデプロイ
- ユーザー認証はLDAPを利用
- HarborへのアクセスにはLoadBalancerを利用
- Rook/Cephを利用しているためBlock Storageの利用にStorageClassの指定が必要
- Private LAN内部では、利用している192.168.x.xのIPについて、DNSのホスト名⇔IPの解決が可能 (dnsmasqを利用)
今回はIntranetからアクセスできるようReverse-Proxy サーバーとしてnginxを経由してHarborにアクセスするケースと、外部からアクセスできないようPrivate LAN内からのみアクセスできるよう設定する2つのケースを利用しました。
ケース1 - NginxをFrontend Reverse-Proxy Serverとして利用する
このケースでは、docker login/push を実行する時に通信に、正規のTLS証明書を利用する点が特徴になります。自己証明TLS鍵を利用するのであれば、Private Network内で利用する方法と同じです。ただ第三者が接続できる可能性があるので、adminパスワードの管理には注意が必要です。
ケース2 - Private Netowrk内でのみ利用する
このケースでは、KubernetesとHarborを同一の独自ネットワークに構築します。dockerコマンドからHarborに接続するためTLS証明書について、独自CAが発行する自己認証鍵になる点が特徴的です。そのためCA鍵をdocker(サーバーの場合)やシステム(クライアントの場合)に登録する必要があります。
TLS鍵の準備には次の2つのシナリオがあります。
- TLS鍵はharborに自動生成させることができ、生成されたCA局の証明書をdockerに登録します
- Private LAN内部で利用するDomain用にeasy-rsa3を利用してCA局を構築する場合は、easy-rsa3が作成するCA局の証明書をdockerに登録します
導入までの流れ
kubectlコマンドが実行できる場所でgit clone
基本的なセットアップ$ git clone https://github.com/goharbor/harbor-helm.git $ cd harbor-helm ## git tag で最新版を確認し、checkoutします。 $ git checkout refs/tags/v1.3.0 -b my_v1.3.0繰り返し作業をいろいろするので、作業用にMakefileを準備しておきます。
git-cloneを実行したディレクトリがCWD$ cd .. ## from harbor-helm $ cat > MakefileMakefileNAMESPACE = harbor HELM_RELEASE = my-harbor .PHONY: init install delete delete-ns check create-tls-secret init: kubectl create ns $(NAMESPACE) install: (cd harbor-helm; helm install --name $(HELM_RELEASE) --namespace $(NAMESPACE) .) delete: (cd harbor-helm; helm delete --purge $(HELM_RELEASE)) delete-ns: kubectl delete ns $(NAMESPACE) check: helm list create-tls-secret: kubectl -n $(NAMESPACE) create secret generic nginx-tls-keys --from-file pki/ca.crt --from-file pki/tls.crt --from-file pki/tls.keyこの部分をCopy&Pasteするとインデントはスペース8個になってしまいますが、タブ文字である点に注意してください。
TLS鍵の配置
values.yamlのsecretName:を空にしたままにすると、TLS鍵が自動的に生成され、secret/helm_release-namespace-nginxに設定されます。今回はca.crt, tls.crt, tls.keyファイルをpki/ディレクトリに準備し、secret/nginx-tls-keysに格納します。
$ make init $ mkdir pki $ cp .../ca.crt .../harbor.example.com.crt .../harbor.example.com.key pki/ $ openssl rsa -in pki/harbor.example.com.key -out pki/harbor.example.com.nopass.key $ ln -s harbor.example.com.crt pki/tls.crt $ ln -s harbor.example.com.nopass.key pki/tls.key $ make create-tls-secretvalues.yamlの編集
git cloneしているので、
git diff
の結果を添付します。これはProxy(proxy.example.com)を経由せずに、直接Private LAN内部でアクセスする場合のものです。Proxy Serverを経由する場合には、externalURL:に外部に公開するProxy ServerのURLを指定します。commonNameにはPrivate LAN内部でDNS名前解決できるホスト名を指定しています。
harbor-helm/values.yamldiff --git a/values.yaml b/values.yaml index 474ffdb..74f9fa5 100644 --- a/values.yaml +++ b/values.yaml @@ -2,7 +2,7 @@ expose: # Set the way how to expose the service. Set the type as "ingress", # "clusterIP", "nodePort" or "loadBalancer" and fill the information # in the corresponding section - type: ingress + type: loadBalancer tls: # Enable the tls or not. Note: if the type is "ingress" and the tls # is disabled, the port must be included in the command when pull/push @@ -16,14 +16,14 @@ expose: # "ca.crt" - the certificate of CA (optional), this enables the download # link on portal to download the certificate of CA # These files will be generated automatically if the "secretName" is not set - secretName: "" + secretName: "nginx-tls-keys" # By default, the Notary service will use the same cert and key as # described above. Fill the name of secret if you want to use a # separated one. Only needed when the type is "ingress". notarySecretName: "" # The common name used to generate the certificate, it's necessary # when the type isn't "ingress" and "secretName" is null - commonName: "" + commonName: "harbor.example.com" ingress: hosts: core: core.harbor.domain @@ -73,7 +73,7 @@ expose: # The name of LoadBalancer service name: harbor # Set the IP if the LoadBalancer supports assigning IP - IP: "" + IP: "192.168.1.43" ports: # The service port Harbor listens on when serving with HTTP httpPort: 80 @@ -98,7 +98,7 @@ expose: # the IP address of k8s node # # If Harbor is deployed behind the proxy, set it as the URL of proxy -externalURL: https://core.harbor.domain +externalURL: https://harbor.example.com # The persistence is enabled by default and a default StorageClass # is needed in the k8s cluster to provision volumes dynamicly. @@ -120,19 +120,19 @@ persistence: # Specify the "storageClass" used to provision the volume. Or the default # StorageClass will be used(the default). # Set it to "-" to disable dynamic provisioning - storageClass: "" + storageClass: "rook-ceph-block" subPath: "" accessMode: ReadWriteOnce - size: 5Gi + size: 20Gi chartmuseum: existingClaim: "" - storageClass: "" + storageClass: "rook-ceph-block" subPath: "" accessMode: ReadWriteOnce size: 5Gi jobservice: existingClaim: "" - storageClass: "" + storageClass: "rook-ceph-block" subPath: "" accessMode: ReadWriteOnce size: 1Gi @@ -140,7 +140,7 @@ persistence: # be ignored database: existingClaim: "" - storageClass: "" + storageClass: "rook-ceph-block" subPath: "" accessMode: ReadWriteOnce size: 1Gi @@ -148,7 +148,7 @@ persistence: # be ignored redis: existingClaim: "" - storageClass: "" + storageClass: "rook-ceph-block" subPath: "" accessMode: ReadWriteOnce size: 1GiHarborのデプロイなどの一連の作業
Makefileを配置したディレクトリは次のようになっています。
$ ls -l total 32 -rw-rw-r-- 1 yasu yasu 219 Jan 9 12:33 Makefile drwxrwxr-x 8 yasu yasu 4096 Jan 9 14:10 harbor-helmnamespaceは既に存在する(make initした)ものとして、helm installを実行します。
$ make install $ make check NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE my-harbor 1 Thu Jan 9 21:37:55 2020 DEPLOYED harbor-1.3.0 1.10.0 harborもしharborを削除したい場合には、make delete, make delete-nsを実行します。delete-nsを実行しない場合には、PVCはnamespace内に残ります。
削除する場合$ make delete $ make check ## my-harborが削除されていれば、delete-nsを実行 $ make delete-ns正常に稼動すればWeb UIなどでログインすることができるようになります。Namespaceのsecretにca.crt,tls.crt,tls.keyを登録済みであれば不要ですが、secretName:を空("")にしてhelmが自動生成する証明書を利用する場合には、ca.crtファイルを抽出して、docker push, kubectl を実行するホスト上に登録する必要があります。
TLS接続時の検証エラーの回避
docker・kubectlコマンドから直接、Harborに接続する場合には、https://docs.docker.com/registry/insecure/ に記述があるように、自己署名CAをそのコマンドを実行するマシンの /etc/docker/certs.d/hostname/ca.crt に配置する方法がお勧めです。
WebブラウザからHarborのWeb UIにアクセスする場合には、そのシステム(Ubuntuであればca-certificatesの管理下)に自己署名CAを登録する方法がお勧めです。
自分が管理していない自己署名CAをシステムに登録する方法はお勧めしませんが、TLS鍵の検証を無視する設定は安直ですができるだけ避けるべきだと思います。自分の管理下にある自己署名CAを登録する方が、対象を限定できるので、お勧めです。
実際に鍵を配布する方法には、ansibleを利用して、全マシンに配布しています。
自己署名CAの抽出
kubectlが実行できるマシンでsecretに登録されているca.tlsの内容を取得します。1行で実行すると次のようになりますが、単純に
$ kubectl get secret my-harbor-harbor-nginx -o yaml
の出力からca.crt部分をコピーして、base64 -dの入力に与える方法もあります。$ kubectl get secret my-harbor-harbor-nginx -o jsonpath='{.data.ca\.crt}' | base64 -d -----BEGIN CERTIFICATE----- ..... -----END CERTIFICATE-----ここで画面に出力された内容を、ca.crtとして保存し、docker pushを実行するホスト、kubernetesの各ノードに登録(/etc/docker/certs.d/harbor.example.com/ca.crtへの配置)をします。
Harborの稼動確認
ca.crtの内容がシステムに登録された後は、Web UIからログインします。
$ firefox https://harbor.example.com/
自己署名CAを利用している場合には警告がでますが、Acceptして次に進みます。
- ID: admin
- Password: Harbor12345
パスワードはログインした後の左上にあるAdminユーザーのメニューから、必ず変更するようにしましょう。LDAPを利用したいので、Configurationに進んで情報を登録しますが、今回は省略します。
Projects "library" へのユーザーの登録
LDAPとの接続ができるようになったところで、自分のIDをProjects"libarary"のMembersタブに進み、"+ USER"ボタンからMasterとして登録しています。
libraryプロジェクトに一般ユーザーを登録したところで、イメージを登録します。
Dockerでのイメージの作成と登録
ネーミングルールは、ホスト名/プロジェクト名/image[:TAG] となっているので、docker buildする場合には適切なtagをつけるか、手元でのテストでも利用すると思うので、次のような方法で、既存のイメージにHarbor登録用の名称を設定するという事になると思います。
実行例$ docker login harbor.example.com Username: user01 Password: $ docker pull nginx:latest $ docker tag nginx:latest harbor.example.com/library/mynginx:1.0 $ docker push harbor.example.com/library/mynginx:1.0 The push refers to repository [harbor.example.com/library/mynginx] 918efb8f161b: Pushed 27dd43ea46a8: Pushed 9f3bfcc4a1a8: Pushed 2dc9f76fb25b: Pushed 1.0: digest: sha256:2695d3e10e69cc500a16eae6d6629c803c43ab075fa5ce60813a0fc49c47e859 size: 1152独自にProjectを登録している場合には、"library"の部分を適宜変更します。
最後にWeb UIから自分のIDでログインし、イメージが登録されていることを確認しておきます。
Kubernetesでのデプロイメントのテスト
次の2つのYAMLファイルを準備します。
deploy-mynginx.yamlapiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: selector: matchLabels: app: nginx replicas: 2 template: metadata: labels: app: nginx spec: imagePullSecrets: - name: selfreg containers: - name: nginx image: harbor.example.com/library/mynginx:1.0 ports: - containerPort: 80svc-mynginx.yamlapiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: type: LoadBalancer ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginxdeploymentの中で参照(.spec.template.spec.imagePullSecrets.name)している、selfregを作成します。
LDAPに登録しているパスワードを$regpasswd変数に格納$ read -s regpasswd ## 入力しているパスワードは非表示な点に注意 $ kubectl -n default create secret docker-registry selfreg --docker-username=user01 --docker-email=user01@example.com --docker-password="${regpasswd}"これで作成した2つのYAMLファイルを登録します。
$ kubectl -n default apply -f deploy-mynginx.yaml $ kubectl -n default apply -f svc-mynginx.yaml ## 状況の確認 $ kubectl -n default get all NAME READY STATUS RESTARTS AGE pod/nginx-deployment-55d5f94b5-nbw4v 1/1 Running 0 43m pod/nginx-deployment-55d5f94b5-wkwb4 1/1 Running 0 43m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 75d service/nginx LoadBalancer 10.233.7.30 192.168.1.24 80:30243/TCP 59m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 2/2 2 2 59m NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-55d5f94b5 2 2 2 43m正常にCAファイルが登録されていない場合には、次のようにエラーになります。
LDAP設定時に注意する点
HarborのLDAP設定は複雑なことができないようになっていて柔軟性には欠けますが、反面、設定自体に困る事はあまりないと思います。
ただ、LDAPサーバーのURLを指定する部分では、次のように設定するとエラーになります。
エラーとなるURL指定ldaps://ldap.example.com:636末尾の :636 の部分は間違いではないはずですが、エラーとなるため
ldaps://ldap.example.com
のように指定する必要がありました。Kubernetesにca.crtが登録されていない場合のエラー
ファイルが正常に配置されていれば再起動は不要ですが、内容が正しくない場合には、次ようなエラーとなります。
$ kubectl -n default describe pod -l app=nginx ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 51s default-scheduler Successfully assigned default/nginx-deployment-55d5f94b5-km9ms to ibox01a2 Normal BackOff 18s (x2 over 43s) kubelet, ibox01a2 Back-off pulling image "harbor.example.com/library/mynginx:1.0" Warning Failed 18s (x2 over 43s) kubelet, ibox01a2 Error: ImagePullBackOff Normal Pulling 4s (x3 over 49s) kubelet, ibox01a2 Pulling image "harbor.example.com/library/mynginx:1.0" Warning Failed 4s (x3 over 44s) kubelet, ibox01a2 Failed to pull image "harbor.example.com/library/mynginx:1.0": rpc error: code = Unknown desc = Error response from daemon: Get https://harbor.example.com/v2/: x509: certificate signed by unknown authority Warning Failed 4s (x3 over 44s) kubelet, ibox01a2 Error: ErrImagePullおよそ、ここまでで一般的なユースケースは満たせるのかなと思います。
以上
- 投稿日:2020-01-15T10:58:47+09:00
DockerでローカルのLambda実行環境を用意する。
はじめに
ファイルの中身のみ記載します。
ディレクトリ構造
. ├── docker-compose.yml ├── lambda ├── sample └── index.jsdocker-compose.ymlの内容
version: '3' services: addData: container_name: sample-lambda image: lambci/lambda:nodejs12.x volumes: - ./lambda/sample:/var/task ports: - 9001:9001 environment: AWS_DEFAULT_REGION: XXXXXXXX AWS_ACCOUNT_ID: YYYYYYYY DOCKER_LAMBDA_WATCH: 1 DOCKER_LAMBDA_STAY_OPEN: 1 command: index.handlerindex.jsの内容
const aws = require("aws-sdk"); exports.handler = async (event, context) => { context.succeed({ statusCode: 200, body : JSON.stringify('hallo sample!'), }); };いざ実行!
dockerの起動
docker-compose upレスポンス確認
別タブで実行
curl -d '{}' http://localhost:9001/2015-03-31/functions/sample/invocationsレスポンス
{"statusCode":200,"body":"\"hallo sample!\""}終わりに
デプロイなんかもDocker使ってできるみたいですね。
時間があれば、そちらも記載したいと思います
- 投稿日:2020-01-15T10:26:49+09:00
Harborのコンパイルとデバッグ
はじめに
HarborをHelmから導入した際に不可解な挙動をしたので、git cloneしたコードをビルドしてみることにしました。その際のメモを残しておきます。
コンパイル & 再コンパイルのプロセス
初期のコンパイルは、公式のガイド https://github.com/goharbor/harbor/blob/master/docs/compile_guide.md に従って操作をします。
$ git clone https://github.com/goharbor/harbor.git $ cd harbor ## git tag で最新版を確認し、checkoutする $ git checkout refs/tags/v1.10.0 -b my_v1.10.0 ## あらかじめTLS鍵ファイルを任意の場所に準備しておき、make/harbor.ymlに記述する ## 今回は、pki/ディレクトリを作成し、配置しておきます $ mkdir pki $ cp ..../pki/issued/harbor.example.com.crt pki/ $ cp ..../pki/private/harbor.example.com.key pki/ ## keyファイルのパスワードを解除します $ openssl rsa -in pki/harbor.example.com.key -out pki/harbor.example.com.nopass.key $ vi make/harbor.ymlmake/harbor.ymlファイルの差分は次のようになっています。
make/harbor.ymldiff --git a/make/harbor.yml b/make/harbor.yml index 4589c352b..83a9ec31d 100644 --- a/make/harbor.yml +++ b/make/harbor.yml @@ -2,7 +2,7 @@ # The IP address or hostname to access admin UI and registry service. # DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients. -hostname: reg.mydomain.com +hostname: harbor.example.com # http related config http: @@ -14,22 +14,22 @@ https: # https port for harbor, default is 443 port: 443 # The path of cert and key files for nginx - certificate: /your/certificate/path - private_key: /your/private/key/path + certificate: ..../git/harbor/pki/harbor.example.com.crt + private_key: ..../git/harbor/pki/harbor.example.com.key # Uncomment external_url if you want to enable external proxy # And when it enabled the hostname will no longer used @@ -24,12 +24,12 @@ https: # The initial password of Harbor admin # It only works in first time to install harbor # Remember Change the admin password from UI after launching Harbor. -harbor_admin_password: Harbor12345 +harbor_admin_password: XXXXXXXXXXXXXX # Harbor DB configuration database: # The password for the root user of Harbor DB. Change this before any production use. - password: root123 + password: XXXXXXXXXXX # The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. max_idle_conns: 50 # The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.ファイルを編集したところでコンパイルを実行しますが、先に挙げた問題を回避するためにsudo makeを利用しています。コンパイル方法の詳細については、https://github.com/goharbor/harbor/blob/master/docs/compile_guide.md を参照してください。
コンパイルの実行$ sudo docker pull golang:1.13.4 $ sudo make install GOBUILDIMAGE=golang:1.13.4 COMPILETAG=compile_golangimageこの操作をした後では、make/harbor.ymlファイルでDBやadminのパスワードを変更し、make cleanall; make install ... を再度実行しても反映されません。
再コンパイル手順
git cloneしたharborディレクトリに移動した後で、作業を行ないます。
$ sudo make down $ sudo make cleanall ## 以下の作業は必要に応じて実施 $ sudo docker system prune -a ## Dockerイメージを登録し直したい場合 $ sudo mv /data /data.old ## DBのパスワード・データなどを初期化・削除した場合ここまでしたら再度make installを実行します。
$ sudo make install GOBUILDIMAGE=golang:1.13.4 COMPILETAG=compile_golangimageEasy-RSAによる鍵ファイルの準備
Easy-RSA3を利用して、独自プライベートネットワーク用ドメイン(example.com)用のCA局を構築しておきます。
easy-rsa-v3によるCA局の準備$ git clone https://github.com/OpenVPN/easy-rsa.git $ cd easy-rsa $ git checkout refs/tags/v3.0.6 -b my_v3.0.6 $ cd .. $ easy-rsa/easyrsa3/easyrsa init-pki $ easy-rsa/easyrsa3/easyrsa build-ca ## Passphraseには出来るだけ長い文字列を指定、CN(Common Name)には対象となるドメインが分かる名称を指定する - e.g. "EXAMPLE.COM Easy-RSA CA" $ ls easy-rsa/ pki/easy-rsa/README.quickstart.md を確認すると、reqファイルは別のマシンで作成するように書かれています。これはkeyファイルとcrtファイルを同一のeas-rsa/ディレクトリ配下に収めてしまう事での情報漏洩を懸念していると思われます。利用する状況に応じて適切にファイルを分離するようにしてください。ここでは禁忌とされている同一マシン上でのgen-req, sign-req clientを実施しています。
また build-server-full, build-client-full オプションの指定があります。今回はそれでもほぼ同じ結果になりますが、柔軟にファイル名と、Common Name(CN)を分離したファイルを作成するためには、gen-req, sign-reqを順番に呼び出す方法を覚えておいた方が便利だと思うので、ここではその方法を記述しています。
"harbor.localdomain"に対応するTLS鍵を生成## easy-rsa/, pki/ が存在するディレクトリで作業を実施 $ easy-rsa/easyrsa3/easyrsa gen-req harbor.example.com ... Keypair and certificate request completed. Your files are: req: .../pki/reqs/harbor.example.com.req key: .../pki/private/harbor.example.com.key $ easy-rsa/easyrsa3/easyrsa sign-req client harbor.example.com $ find pki -type f | grep harbor.example.com pki/reqs/harbor.example.com.req pki/issued/harbor.example.com.crt pki/private/harbor.example.com.key"harbor.example.com"の部分はプライベートネットワーク内部で名前解決できるホスト名を指定します。準備したcrtファイルとkeyファイルをmake/harbor.ymlに指定します。pki/ca.crtファイルは利用するシステムが認識できるように登録しておきます。
Ubuntu 18.04上での自己証明TLSファイルの登録について
作業やFirefoxなどのWeb UIへのアクセスをするUbuntu 18.04ホスト上ではシステムにCAファイルを登録します。ca-certificatesパッケージが導入されている場合には、次の方法が基本的なフローになります。
- /usr/share/ca-certificates/ 以下に(通常はサブディレクトリを作成して)任意の名前(通常は"harbor.example.com.crt"のように、FQDN+".crt")でCAファイルを配置
- /etc/ca-certificates.conf に /usr/share/ca-certificates/ からの相対パスで、配置したCAファイルを登録
$ sudo update-ca-certificates
を実行作業の結果は、/etc/ssl/certs/ ディレクトリに反映されますが、直接ここにファイルを配置する方法はお勧めしません。
実行例$ sudo mkdir /usr/share/ca-certificates/local $ sudo cp pki/ca.crt /usr/share/ca-certificates/local/harbor.example.com $ sudo vi /etc/ca-certificates.conf $ tail /etc/ca-certificates.conf ... local/harbor.example.com.crt $ sudo update-ca-certificatesfirefoxが実行中であれば、再起動が必要です。
Kubernetes上へのCAファイルの配置
既に説明したように、/etc/docker/certs.d/以下に配置します。ansibleでは該当ディレクトリをあらかじめ作成する必要があるので、ちゃんとtasks/main.ymlなどにTASKを追加するか、
$ ansible all -m command -b -a "mkdir -p /etc/docker/certs.d/_hostname__"
のようにディレクトリを準備します。("hostname"の部分はdocker loginの引数に指定するホスト名に変更)コンパイル時に遭遇した問題
- 一般ユーザーでmakeコマンドを実行すると、harbor/make/common/config/log/logrotate.conf の書き込み権限がないためmakeに失敗する (golangにDockerイメージを利用する際に作成されるファイルのUID,GIDが1000:1000となる。もしUID,GIDが一致していればこのエラーには遭遇しないかもしれません)
- TLS用のcert,keyファイルを準備・指定する必要がある
make installによってdocker runまで実行されるため、(何も設定していなければ)root権限が必要になる
についてはsudo makeで回避します。2.については今後のためにもプライベートネットワークで利用するCA局をeasy-rsaを利用して構築しておきます。
Helmでtls:falseの際に、遭遇した unknown blob エラー について
tls: falseのまま
$ helm install
した場合、TLSを有効にしたReverse-Proxyを配置することで、docker loginまでは成功します。しかし、私の環境ではdocker pushの最後にunknown blobと表示されて失敗するエラーに遭遇しました。フロントエンドでTLSを有効にしたReverse-Proxy Serverを設置して、HTTPでHarborに通信させようとすると、エラーが発生します。nginxのノードはNAPT-gatewayとしても機能している<------ global ip space --------><------------ private address space ----------> +----------+ +-------+ +--------------+ +-----+ | Intranet |---TLS(443)---| nginx |---non-TLS(80)---| LoadBalancer |---| Pod | +----------+ ↑ +-------+ +--------------+ +-----+ ↑ ↑ (※ tls: false) ↑ (proxy_pass: http://kubeweb.example.com;) (https://harbor.example.com/)この前段まででは、ここで不具合が発生しているのと、docker/kubernetesはregistryとの通信にTLSを前提としているので、原因が100%はっきりしているわけではないですが、前段まではtls: trueを前提とした構成を説明しています。
エラーが発生した状況$ sudo docker login example.com $ sudo docker build . --tag proxy.example.com/library/mynginx:1.0 --no-cache $ sudo docker push example.com/library/mynginx:1.0 4fc1aa8003a3: Pushing 3.584kB 5fb987d2e54d: Preparing 831c5620387f: Pushing 69.21MB/69.21MB unknown blobproxy.example.comは正式なTLS鍵を利用していて、通信自体は問題なく行なえています。しかし、この時のReverse-Proxy nginxのログを確認すると、次のようになっています。
エラーと関連するaccess_log... 192.168.1.240 - - [09/Jan/2020:22:03:30 +0900] "HEAD /v2/library/mynginx/blobs/sha256:eb22865337de3edb54ec8b52f6c06de320f415e7ec43f01426fdafb8df6d6eb7 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" 192.168.1.240 - - [09/Jan/2020:22:03:30 +0900] "HEAD /v2/library/mynginx/blobs/sha256:bee5d581ef8bfee2b5a54685813ba6ad9bbe922115d7aef84a21a9dbfcc2d979 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" ...この状態のregistry podの/storage以下は次のようになっていて、pushされたイメージがそのまま保存されたまま、処理されていない様子が分かります。
エラーが発生する場合_uploads/以下のみ存在$ kc exec -it my-harbor-harbor-registry-79767646d6-rbv6j find /storage ... /storage/docker/registry/v2/repositories/library/mynginx /storage/docker/registry/v2/repositories/library/mynginx/_uploads /storage/docker/registry/v2/repositories/library/mynginx/_uploads/bbe0e1fa-2d97-4b55-8d4d-a41ed2ca7c3a /storage/docker/registry/v2/repositories/library/mynginx/_uploads/bbe0e1fa-2d97-4b55-8d4d-a41ed2ca7c3a/hashstates ...正常に動作しているHarborでは、.../_uploads/ディレクトリは空になって,library以下にイメージのメタ情報、blobs以下にイメージファイルが展開されています。
正常に稼動している場合$ kubectl exec -it my-harbor-harbor-registry-57dc985f45-mql55 find /storage /storage/docker/registry/v2/repositories/library /storage/docker/registry/v2/repositories/library/mynginx /storage/docker/registry/v2/repositories/library/mynginx/_uploads /storage/docker/registry/v2/repositories/library/mynginx/_layers /storage/docker/registry/v2/repositories/library/mynginx/_manifests/tags/1.0/current/link ... /storage/docker/registry/v2/blobs/sha256 /storage/docker/registry/v2/blobs/sha256/be /storage/docker/registry/v2/blobs/sha256/be/bee5d581ef... ..._uploads/に配置されたファイルを処理して、library/, blobs/に展開する処理をするコードを探してみます。
$ git clone https://github.com/goharbor/harbor.git $ cd harbor $ find . -type f -exec grep _uploads {} \; -print ## 結果が表示されなかったregistory上の/storageに存在するので、何かしらそこに配置された理由があるはずですが、harborのコード中には原因がなさそうです。コードを詳細に読む前に、再現させてnginxのログファイルをもう少し詳しくみていこうと思います。
docker-push時のreverse-proxyログの抜粋92.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "GET /v2/ HTTP/1.1" 401 87 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - user01 [10/Jan/2020:15:01:36 +0900] "GET /service/token?account=user01&scope=repository%3Alibrary%2Fmynginx%3Apush%2Cpull&service=harbor-registry HTTP/1.1" 200 984 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:8...d HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:d...7 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:b...6 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/8...d?_state=m...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/8...d?_state=m...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/5...5?_state=-8...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/5...5?_state=-8...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/9...c?_state=E...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/9...c?_state=E...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/9...c?_state=o...9&digest=sha256%3A1...9 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/9...c?_state=o...9&digest=sha256%3A1...9" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/5...5?_state=W...6 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/5...5?_state=W...6" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/8...d?_state=...9&digest=sha256%3A7...0 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/8...d?_state=i...9&digest=sha256%3A7...0" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:7...0 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:1...9 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:b...6 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-"この時にregistory podの/storageは次のようになっていて、library/ubuntu/_uploads以外にはファイルが存在しない状態です。
$ /storage /storage/docker /storage/docker/registry /storage/docker/registry/v2 /storage/docker/registry/v2/repositories /storage/docker/registry/v2/repositories/library /storage/docker/registry/v2/repositories/library/ubuntu /storage/docker/registry/v2/repositories/library/ubuntu/_uploads /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates/sha256 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates/sha256/0 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/data /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/startedat ....
ひとまずHarborを自分でコンパイルしてみて、_uploadsに配置されたファイルがblobsに移動されるまでの処理のどこに問題があるのか調べていきます。issuesを眺める限りは再現性がなく、いつのまにか解決しているようです。
以上
- 投稿日:2020-01-15T10:26:49+09:00
Harborのコンパイルとデバッグ with easy-rsa3
はじめに
HarborをHelmから導入した際に不可解な挙動をしたので、git cloneしたコードをビルドしてみることにしました。その際のメモを残しておきます。
コンパイル & 再コンパイルのプロセス
初期のコンパイルは、公式のガイド https://github.com/goharbor/harbor/blob/master/docs/compile_guide.md に従って操作をします。
$ git clone https://github.com/goharbor/harbor.git $ cd harbor ## git tag で最新版を確認し、checkoutする $ git checkout refs/tags/v1.10.0 -b my_v1.10.0 ## あらかじめTLS鍵ファイルを任意の場所に準備しておき、make/harbor.ymlに記述する ## 今回は、pki/ディレクトリを作成し、配置しておきます $ mkdir pki $ cp ..../pki/issued/harbor.example.com.crt pki/ $ cp ..../pki/private/harbor.example.com.key pki/ ## keyファイルのパスワードを解除します $ openssl rsa -in pki/harbor.example.com.key -out pki/harbor.example.com.nopass.key $ vi make/harbor.ymlmake/harbor.ymlファイルの差分は次のようになっています。
make/harbor.ymldiff --git a/make/harbor.yml b/make/harbor.yml index 4589c352b..83a9ec31d 100644 --- a/make/harbor.yml +++ b/make/harbor.yml @@ -2,7 +2,7 @@ # The IP address or hostname to access admin UI and registry service. # DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients. -hostname: reg.mydomain.com +hostname: harbor.example.com # http related config http: @@ -14,22 +14,22 @@ https: # https port for harbor, default is 443 port: 443 # The path of cert and key files for nginx - certificate: /your/certificate/path - private_key: /your/private/key/path + certificate: ..../git/harbor/pki/harbor.example.com.crt + private_key: ..../git/harbor/pki/harbor.example.com.key # Uncomment external_url if you want to enable external proxy # And when it enabled the hostname will no longer used @@ -24,12 +24,12 @@ https: # The initial password of Harbor admin # It only works in first time to install harbor # Remember Change the admin password from UI after launching Harbor. -harbor_admin_password: Harbor12345 +harbor_admin_password: XXXXXXXXXXXXXX # Harbor DB configuration database: # The password for the root user of Harbor DB. Change this before any production use. - password: root123 + password: XXXXXXXXXXX # The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. max_idle_conns: 50 # The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.ファイルを編集したところでコンパイルを実行しますが、先に挙げた問題を回避するためにsudo makeを利用しています。コンパイル方法の詳細については、https://github.com/goharbor/harbor/blob/master/docs/compile_guide.md を参照してください。
コンパイルの実行$ sudo docker pull golang:1.13.4 $ sudo make install GOBUILDIMAGE=golang:1.13.4 COMPILETAG=compile_golangimageこの操作をした後では、make/harbor.ymlファイルでDBやadminのパスワードを変更し、make cleanall; make install ... を再度実行しても反映されません。
再コンパイル手順
git cloneしたharborディレクトリに移動した後で、作業を行ないます。
$ sudo make down $ sudo make cleanall ## 以下の作業は必要に応じて実施 $ sudo docker system prune -a ## Dockerイメージを登録し直したい場合 $ sudo mv /data /data.old ## DBのパスワード・データなどを初期化・削除した場合ここまでしたら再度make installを実行します。
$ sudo make install GOBUILDIMAGE=golang:1.13.4 COMPILETAG=compile_golangimageEasy-RSAによる鍵ファイルの準備
Easy-RSA3を利用して、独自プライベートネットワーク用ドメイン(example.com)用のCA局を構築しておきます。
easy-rsa-v3によるCA局の準備$ git clone https://github.com/OpenVPN/easy-rsa.git $ cd easy-rsa $ git checkout refs/tags/v3.0.6 -b my_v3.0.6 $ cd .. $ easy-rsa/easyrsa3/easyrsa init-pki $ easy-rsa/easyrsa3/easyrsa build-ca ## Passphraseには出来るだけ長い文字列を指定、CN(Common Name)には対象となるドメインが分かる名称を指定する - e.g. "EXAMPLE.COM Easy-RSA CA" $ ls easy-rsa/ pki/easy-rsa/README.quickstart.md を確認すると、reqファイルは別のマシンで作成するように書かれています。これはkeyファイルとcrtファイルを同一のeas-rsa/ディレクトリ配下に収めてしまう事での情報漏洩を懸念していると思われます。利用する状況に応じて適切にファイルを分離するようにしてください。ここでは禁忌とされている同一マシン上でのgen-req, sign-req clientを実施しています。
また build-server-full, build-client-full オプションの指定があります。今回はそれでもほぼ同じ結果になりますが、柔軟にファイル名と、Common Name(CN)を分離したファイルを作成するためには、gen-req, sign-reqを順番に呼び出す方法を覚えておいた方が便利だと思うので、ここではその方法を記述しています。
"harbor.localdomain"に対応するTLS鍵を生成## easy-rsa/, pki/ が存在するディレクトリで作業を実施 $ easy-rsa/easyrsa3/easyrsa gen-req harbor.example.com ... Keypair and certificate request completed. Your files are: req: .../pki/reqs/harbor.example.com.req key: .../pki/private/harbor.example.com.key $ easy-rsa/easyrsa3/easyrsa sign-req client harbor.example.com $ find pki -type f | grep harbor.example.com pki/reqs/harbor.example.com.req pki/issued/harbor.example.com.crt pki/private/harbor.example.com.key"harbor.example.com"の部分はプライベートネットワーク内部で名前解決できるホスト名を指定します。準備したcrtファイルとkeyファイルをmake/harbor.ymlに指定します。pki/ca.crtファイルは利用するシステムが認識できるように登録しておきます。
Ubuntu 18.04上での自己証明TLSファイルの登録について
Ubuntu 18.04ホスト上ではシステムにCAファイルを登録する場合について説明します。ca-certificatesパッケージが導入されている場合には、次の方法が基本的なフローになります。
- /usr/share/ca-certificates/ 以下に(通常はサブディレクトリを作成して)任意の名前(通常は"harbor.example.com.crt"のように、FQDN+".crt")でCAファイルを配置
- /etc/ca-certificates.conf に /usr/share/ca-certificates/ からの相対パスで、配置したCAファイルを登録
$ sudo update-ca-certificates
を実行作業の結果は、/etc/ssl/certs/ ディレクトリに反映されますが、直接ここにファイルを配置する方法はお勧めしません。
実行例$ sudo mkdir /usr/share/ca-certificates/local $ sudo cp pki/ca.crt /usr/share/ca-certificates/local/harbor.example.com $ sudo vi /etc/ca-certificates.conf $ tail /etc/ca-certificates.conf ... local/harbor.example.com.crt $ sudo update-ca-certificatesFirefoxへの自己証明CA情報の登録
この記事、https://askubuntu.com/questions/244582/add-certificate-authorities-system-wide-on-firefox にあるように、firefoxでは自前のcertificate DBを利用するため、ca-certificatesが準備する /etc/ssl/cets/ ファイルは利用できません。そのため certutils を利用して、sqlite DBを更新する方法が紹介されていますが、2020年1月時点では、プロファイルをリセットしても空になっているなど、変更できない挙動のように感じられます。
Web-UIにアクセスする際には、Advanced... → Accept の流れで、一時的に接続を許可しています。
Kubernetes上へのCAファイルの配置
既に説明したように、/etc/docker/certs.d/以下に配置します。ansibleでは該当ディレクトリをあらかじめ作成する必要があるので、ちゃんとtasks/main.ymlなどにTASKを追加するか、
$ ansible all -m command -b -a "mkdir -p /etc/docker/certs.d/_hostname__"
のようにディレクトリを準備します。("hostname"の部分はdocker loginの引数に指定するホスト名に変更)Harborのコンパイル時に遭遇した問題
- 一般ユーザーでmakeコマンドを実行すると、harbor/make/common/config/log/logrotate.conf の書き込み権限がないためmakeに失敗する (golangにDockerイメージを利用する際に作成されるファイルのUID,GIDが1000:1000となる。もしUID,GIDが一致していればこのエラーには遭遇しないかもしれません)
- TLS用のcert,keyファイルを準備・指定する必要がある
make installによってdocker runまで実行されるため、(何も設定していなければ)root権限が必要になる
についてはsudo makeで回避します。2.については今後のためにもプライベートネットワークで利用するCA局をeasy-rsaを利用して構築しておきます。
Helmでtls:falseの際に、遭遇した unknown blob エラー について
tls: falseのまま
$ helm install
した場合、TLSを有効にしたReverse-Proxyを配置することで、docker loginまでは成功します。しかし、私の環境ではdocker pushの最後にunknown blobと表示されて失敗するエラーに遭遇しました。フロントエンドでTLSを有効にしたReverse-Proxy Serverを設置して、HTTPでHarborに通信させようとすると、エラーが発生します。nginxのノードはNAPT-gatewayとしても機能している<------ global ip space --------><------------ private address space ----------> +----------+ +-------+ +--------------+ +-----+ | Intranet |---TLS(443)---| nginx |---non-TLS(80)---| LoadBalancer |---| Pod | +----------+ ↑ +-------+ +--------------+ +-----+ ↑ ↑ (※ tls: false) ↑ (proxy_pass: http://kubeweb.example.com;) (https://harbor.example.com/)この前段まででは、ここで不具合が発生しているのと、docker/kubernetesはregistryとの通信にTLSを前提としているので、原因が100%はっきりしているわけではないですが、前段まではtls: trueを前提とした構成を説明しています。
エラーが発生した状況$ sudo docker login example.com $ sudo docker build . --tag proxy.example.com/library/mynginx:1.0 --no-cache $ sudo docker push example.com/library/mynginx:1.0 4fc1aa8003a3: Pushing 3.584kB 5fb987d2e54d: Preparing 831c5620387f: Pushing 69.21MB/69.21MB unknown blobproxy.example.comは正式なTLS鍵を利用していて、通信自体は問題なく行なえています。しかし、この時のReverse-Proxy nginxのログを確認すると、次のようになっています。
エラーと関連するaccess_log... 192.168.1.240 - - [09/Jan/2020:22:03:30 +0900] "HEAD /v2/library/mynginx/blobs/sha256:eb22865337de3edb54ec8b52f6c06de320f415e7ec43f01426fdafb8df6d6eb7 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" 192.168.1.240 - - [09/Jan/2020:22:03:30 +0900] "HEAD /v2/library/mynginx/blobs/sha256:bee5d581ef8bfee2b5a54685813ba6ad9bbe922115d7aef84a21a9dbfcc2d979 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" ...この状態のregistry podの/storage以下は次のようになっていて、pushされたイメージがそのまま保存されたまま、処理されていない様子が分かります。
エラーが発生する場合_uploads/以下のみ存在$ kc exec -it my-harbor-harbor-registry-79767646d6-rbv6j find /storage ... /storage/docker/registry/v2/repositories/library/mynginx /storage/docker/registry/v2/repositories/library/mynginx/_uploads /storage/docker/registry/v2/repositories/library/mynginx/_uploads/bbe0e1fa-2d97-4b55-8d4d-a41ed2ca7c3a /storage/docker/registry/v2/repositories/library/mynginx/_uploads/bbe0e1fa-2d97-4b55-8d4d-a41ed2ca7c3a/hashstates ...正常に動作しているHarborでは、.../_uploads/ディレクトリは空になって,library以下にイメージのメタ情報、blobs以下にイメージファイルが展開されています。
正常に稼動している場合$ kubectl exec -it my-harbor-harbor-registry-57dc985f45-mql55 find /storage /storage/docker/registry/v2/repositories/library /storage/docker/registry/v2/repositories/library/mynginx /storage/docker/registry/v2/repositories/library/mynginx/_uploads /storage/docker/registry/v2/repositories/library/mynginx/_layers /storage/docker/registry/v2/repositories/library/mynginx/_manifests/tags/1.0/current/link ... /storage/docker/registry/v2/blobs/sha256 /storage/docker/registry/v2/blobs/sha256/be /storage/docker/registry/v2/blobs/sha256/be/bee5d581ef... ..._uploads/に配置されたファイルを処理して、library/, blobs/に展開する処理をするコードを探してみます。
$ git clone https://github.com/goharbor/harbor.git $ cd harbor $ find . -type f -exec grep _uploads {} \; -print ## 結果が表示されなかったregistory上の/storageに存在するので、何かしらそこに配置された理由があるはずですが、harborのコード中には原因がなさそうです。コードを詳細に読む前に、再現させてnginxのログファイルをもう少し詳しくみていこうと思います。
docker-push時のreverse-proxyログの抜粋92.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "GET /v2/ HTTP/1.1" 401 87 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - user01 [10/Jan/2020:15:01:36 +0900] "GET /service/token?account=user01&scope=repository%3Alibrary%2Fmynginx%3Apush%2Cpull&service=harbor-registry HTTP/1.1" 200 984 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:8...d HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:d...7 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:36 +0900] "HEAD /v2/library/mynginx/blobs/sha256:b...6 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "POST /v2/library/mynginx/blobs/uploads/ HTTP/1.1" 202 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/8...d?_state=m...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/8...d?_state=m...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/5...5?_state=-8...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/5...5?_state=-8...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:37 +0900] "GET /v2/library/mynginx/blobs/uploads/9...c?_state=E...Q%3D%3D HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/9...c?_state=E...Q%3D%3D" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/9...c?_state=o...9&digest=sha256%3A1...9 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/9...c?_state=o...9&digest=sha256%3A1...9" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/5...5?_state=W...6 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/5...5?_state=W...6" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "GET /v2/library/mynginx/blobs/uploads/8...d?_state=...9&digest=sha256%3A7...0 HTTP/1.1" 204 0 "http://inovtst9.u-aizu.ac.jp/v2/library/mynginx/blobs/uploads/8...d?_state=i...9&digest=sha256%3A7...0" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:7...0 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:1...9 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-" 192.168.1.240 - - [10/Jan/2020:15:01:38 +0900] "HEAD /v2/library/mynginx/blobs/sha256:b...6 HTTP/1.1" 404 0 "-" "docker/19.03.5 go/go1.12.12 git-commit/633a0ea838 kernel/4.15.0-74-generic os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.5 \x5C(linux\x5C))" "-"この時にregistory podの/storageは次のようになっていて、library/ubuntu/_uploads以外にはファイルが存在しない状態です。
$ /storage /storage/docker /storage/docker/registry /storage/docker/registry/v2 /storage/docker/registry/v2/repositories /storage/docker/registry/v2/repositories/library /storage/docker/registry/v2/repositories/library/ubuntu /storage/docker/registry/v2/repositories/library/ubuntu/_uploads /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates/sha256 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/hashstates/sha256/0 /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/data /storage/docker/registry/v2/repositories/library/ubuntu/_uploads/fc83002e-b800-4ef2-bbab-16d2014fbc82/startedat ....
ひとまずHarborを自分でコンパイルしてみて、_uploadsに配置されたファイルがblobsに移動されるまでの処理のどこに問題があるのか調べていきます。issuesを眺める限りは再現性がなく、いつのまにか解決しているようです。
以上
- 投稿日:2020-01-15T09:30:08+09:00
今日のdocker 作業
OSを10.15.2 に上げた。
zshLast login: Wed Jan 15 08:56:14 on ttys001 The default interactive shell is now zsh. To update your account to use zsh, please run `chsh -s /bin/zsh`. For more details, please visit https://support.apple.com/kb/HT208050. $ sw_vers ProductName: Mac OS X ProductVersion: 10.15.2 BuildVersion: 19C57 $ system_profiler SPSoftwareDataType Software: System Software Overview: System Version: macOS 10.15.2 (19C57) Kernel Version: Darwin 19.2.0 Boot Volume: Macintosh HD Boot Mode: Normal Computer Name: my_com_name User Name: my_name (my_name) Secure Virtual Memory: Enabled System Integrity Protection: Enabled Time since boot: 22:56 $ uname -a Darwin KM-S05.local 19.2.0 Darwin Kernel Version 19.2.0: Sat Nov 9 03:47:04 PST 2019; root:xnu-6153.61.1~20/RELEASE_X86_64 x86_64 $ $ uname -p i386 $ cat /System/Library/CoreServices/SystemVersion.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>ProductBuildVersion</key> <string>19C57</string> <key>ProductCopyright</key> <string>1983-2019 Apple Inc.</string> <key>ProductName</key> <string>Mac OS X</string> <key>ProductUserVisibleVersion</key> <string>10.15.2</string> <key>ProductVersion</key> <string>10.15.2</string> <key>iOSSupportVersion</key> <string>13.0</string> </dict> </plist> $ brew update Updated 2 taps (homebrew/core and homebrew/cask). ==> Updated Formulae ack assimp bitrise libsixel opa acpica atlassian-cli conan libtensorflow rhino ammonite-repl azure-cli exploitdb minio-mc serverless artifactory babel firebase-cli mysql snapcraft ask-cli balena-cli kind okteto terragrunt $ brew upgradedocker(19) 言語処理100本ノックをdockerで。python覚えるのに最適。
https://qiita.com/kaizen_nagoya/items/7e7eb7c543e0c18438c4zsh$ docker run -v /tmp/work:/tmp/work -p 8080:8080 -it kaizenjapan/100pon /bin/bash Unable to find image 'kaizenjapan/100pon:latest' locally latest: Pulling from kaizenjapan/100pon 05d1a5232b46: Already exists 33529d049adc: Already exists be72550a31b7: Already exists 40cab810eef6: Extracting 1.312MB/1.312MB 90a7cfada776: Download complete 63b10c589b27: Download complete 3b74f2e93e93: Download complete 4ad328879d5f: Downloading 113.9MB/985.1MB 53bb48f40962: Downloading 126.7MB/2.076GB 7430ebce441f: Download complete 152f700bf3d8: Downloading 49.91MB/3.14GB1) Already exists
すでにdocker で ubuntuなどを起動したことがある場合
2) Downloading
現在Downloading中
3) Download complete
4) Extracting
参考資料(reference)
macOS (OS X, Mac OS X) のバージョンを調べるコマンドやファイル
https://qiita.com/niwasawa/items/1b12ad162abb7f84eff9
- 投稿日:2020-01-15T09:30:08+09:00
今日のdocker エラー: failed to register layer:
OSを10.15.2 に上げた。
macOS
zshLast login: Wed Jan 15 08:56:14 on ttys001 The default interactive shell is now zsh. To update your account to use zsh, please run `chsh -s /bin/zsh`. For more details, please visit https://support.apple.com/kb/HT208050. $ sw_vers ProductName: Mac OS X ProductVersion: 10.15.2 BuildVersion: 19C57 $ system_profiler SPSoftwareDataType Software: System Software Overview: System Version: macOS 10.15.2 (19C57) Kernel Version: Darwin 19.2.0 Boot Volume: Macintosh HD Boot Mode: Normal Computer Name: my_com_name User Name: my_name (my_name) Secure Virtual Memory: Enabled System Integrity Protection: Enabled Time since boot: 22:56 $ uname -a Darwin KM-S05.local 19.2.0 Darwin Kernel Version 19.2.0: Sat Nov 9 03:47:04 PST 2019; root:xnu-6153.61.1~20/RELEASE_X86_64 x86_64 $ $ uname -p i386 $ cat /System/Library/CoreServices/SystemVersion.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>ProductBuildVersion</key> <string>19C57</string> <key>ProductCopyright</key> <string>1983-2019 Apple Inc.</string> <key>ProductName</key> <string>Mac OS X</string> <key>ProductUserVisibleVersion</key> <string>10.15.2</string> <key>ProductVersion</key> <string>10.15.2</string> <key>iOSSupportVersion</key> <string>13.0</string> </dict> </plist> $ brew update Updated 2 taps (homebrew/core and homebrew/cask). ==> Updated Formulae ack assimp bitrise libsixel opa acpica atlassian-cli conan libtensorflow rhino ammonite-repl azure-cli exploitdb minio-mc serverless artifactory babel firebase-cli mysql snapcraft ask-cli balena-cli kind okteto terragrunt $ brew upgradedocker
docker(19) 言語処理100本ノックをdockerで。python覚えるのに最適。
https://qiita.com/kaizen_nagoya/items/7e7eb7c543e0c18438c4zsh$ docker run -v /tmp/work:/tmp/work -p 8080:8080 -it kaizenjapan/100pon /bin/bash Unable to find image 'kaizenjapan/100pon:latest' locally latest: Pulling from kaizenjapan/100pon 05d1a5232b46: Already exists 33529d049adc: Already exists be72550a31b7: Already exists 40cab810eef6: Extracting 1.312MB/1.312MB 90a7cfada776: Download complete 63b10c589b27: Download complete 3b74f2e93e93: Download complete 4ad328879d5f: Downloading 113.9MB/985.1MB 53bb48f40962: Downloading 126.7MB/2.076GB 7430ebce441f: Download complete 152f700bf3d8: Downloading 49.91MB/3.14GB1) Already exists
すでにdocker で ubuntuなどを起動したことがある場合
2) Downloading
現在Downloading中
3) Download complete
4) Extracting
docker error
zsh$ docker run -v /tmp/work:/tmp/work -p 8080:8080 -it kaizenjapan/100pon /bin/bash Unable to find image 'kaizenjapan/100pon:latest' locally latest: Pulling from kaizenjapan/100pon 05d1a5232b46: Already exists 33529d049adc: Already exists be72550a31b7: Already exists 40cab810eef6: Extracting 1.312MB/1.312MB 90a7cfada776: Download complete 63b10c589b27: Download complete 3b74f2e93e93: Download complete 4ad328879d5f: Download complete 53bb48f40962: Download complete 7430ebce441f: Download complete 152f700bf3d8: Download complete docker: failed to register layer: open /var/lib/docker/overlay2/598c537285d52ff0ae3bd2e551b1beba59e5608993a09ee3da118d9782ea4704/link: no such file or directory.参考資料(reference)
macOS (OS X, Mac OS X) のバージョンを調べるコマンドやファイル
https://qiita.com/niwasawa/items/1b12ad162abb7f84eff9
- 投稿日:2020-01-15T00:41:57+09:00
Dockerでnode.jsプロジェクトの開発環境構築
動機
- 新しくMac Book Pro 2019を購入。nodeやpytonの開発環境構築にあたっては, 素の環境を綺麗なままにしたいことや、いろいろな環境での開発を行いためDockerを用いることにした。
- Docker周りの設定や概念の理解で少し躓いたのでここに記す。エキスパートには当たり前すぎる内容だとしてもだ。
やりたいこと
node.js, angular, ionic, webpack を使ったweb appやPWAの開発を、
- ホストのローカル環境を汚すことなく(Dockerを用い)
- ホストで動くVS Codeを用いたコーディング&デバッグしつつ
- ホストのターミナルからgitを用いたバージョニングしつつ
- 仮想マシンでionic server等で起動したサーバとその上で動くweb appを、ホストのブラウザからアクセスし動作確認・デバッグ手順
1. Docker desktop for Macをインストール
https://hub.docker.com からダウンロード。ユーザ登録も済ます。
2. プロジェクトのディレクトリ構造
最終的に下記になります。順番に作っていきましょう。
- Dockerfile - docker-compose.yml - app |- ここに諸々のソースを置く3. Dockerfile
Dockerfie
: Imageを作成する設定ファイル
Image
: 仮想マシンの雛形。OS, インストールされたソフトウェアセット等からなる。node.js入りのalpine linuxのimageをベースに、ionicとcordovaをインストールしたimageを作成する。
alpine linux
: 超軽量linux. Dockerの仮想マシンOSとして頻繁に利用されている.host$ cat Dockerfile FROM node:10.13-alpine WORKDIR /app RUN npm install -g ionic cordova CMD ["sh"]下記コマンドでDocker imageを作成します。最初に実行する場合ローカルにnode:10.13-alpineのイメージがないのでdocker hubからダウンロードされてきます。2回目以降はローカルのイメージが使われます。
host$ docker build . -t watashino-image-tはイメージの名前を与えるオプションです。適当につけてOK。
正常に完了すればdocker imagesでimageが作成されていることが確認できます。nodeのイメージもダウンロードされローカルに保存されています。host$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE watashino-image latest da6f921ba540 2 minutes ago 133MB node 10.13-alpine 93f2dcbcddfe 13 months ago 70.3MB
このimageが仮想マシンの雛形となります。
4. docker-compose.yml
続いて、imageを実際に起動するためのファイルを記述します。
docker-compose.yml
: docker-composeというコマンドへ与える設定ファイル
docker-compose
:imageからcontainerを作成・起動するプログラム。
container
: 厳密な話は置いておいて、ざっくりいうと、雛形であるimageから作成された仮想マシンを表す。型とそのインスタンス、という関係に近い。実際のところ、"docker"コマンドだけでもcontainerの作成・起動はできるが、オプションの指定等が面倒だったり複数のcontainerの起動等も同時に行えるdocker-composeの方が便利そうなので、最初からこちらを採用。
host$ cat docker-compose.yml version: '3' services: app: build: . image: watashino-image volumes: - ./app:/app ports: - "8100:8100" tty: true下記のコマンドでcontainerの作成・起動。まだローカルにappフォルダを作っていない場合には作っておく。
host$ mkdir app $ docker-compose up -d何事もなくコマンドが終了すれば成功。仮想マシンはバックグラウンドで動作している。下記コマンドで実行中のcontainerの一覧が見れる。
host$ docker ps
お気づきの方もいるでしょうが、実はstep 3のdocker buildのコマンドは実行しなくてもよかったのです。"build: ."の行はビルドに関する指示で、docker-composeファイルは指定されたimageが存在しない場合には自動的にDockerfileを参照してimageのbuildと、続いてcontaierの作成と起動を行います。imageとcontainerの関係を明らかにするために冗長な手順とさせてもらいました。
他の設定の意味:
services
docker-composeでは仮想マシンをserviceという呼び方をするようです。ここでは"app"というサービスを一つ定義しています。複数の仮想マシン=サービスの設定を書いてまとめて起動することもできます。というかそれこそがdocker-composeが便利な点で使う理由です。
volumes
ローカルの./appフォルダと仮想マシンにおける/app (root直下)を結びつけます。これによより仮想マシンとホストマシンのファイルが同期されるようになります。
ports
ポートフィワーディングの設定。仮想マシンのport 8100とローカルのport 8100を結びつけます。仮想マシンにおけるlocalhost:8100に、ホストマシンからlocalhost:8100でアクセスできるようになります。(ただし後述の注意点あり)
tty
これがtrueではないと、containerは起動後すぐに終了してしまう。5. 動作中の仮想マシンを操作
バックグランドで実行されているcontainerには下記のコマンドでアクセスできます。
host$ docker exec app sh何をしているかというとappサービス(docker-compose.xmlで指定した名称)でshの実行を指示しています。上記を実行するとシェルで仮想環境の中をいじれるようになります。
仮想環境から退出するには
container# exit
します。
6. gitからソースを持ってくる&VS Codeで読み込む
app以下にソースコードを持ってきましょう。ローカルのappフォルダで通常通りgitでソースファイルを持ってきます。
host$ cd app $ git clone アドレス仮想環境にgitをinstallすれば仮想環境で直接gitを使えるでしょうが(未確認)、わざわざそうする必要もないかと思います。
ファイルは同期されていますから、特に意識することなくローカル環境のVS Codeを開き、ローカルのappフォルダを開けばOK
7. 仮想環境でビルド&実行
host$ docker-compose exec app shで仮想環境に入りappフォルダを覗けばソースコードが見えるはずです。あとは通常通りの開発ルーチンに従います。ここではionicプロジェクトの例では、下記のようなことを行います。ionic(ng)のビルドインサーバをポートフォワーディングで設定したportで起動しています。
container# npm install # ionic serve -p 8100 --address 0.0.0.0これによりホスト環境から localhost:8100 で仮想環境内のWEBサーバにアクセスできます。--address 0.0.0.0 を付けないとホストからは見れません。理由はこちらをご参考ください。
8. Containerの停止, 再開
開発が終わったら起動させておくのは無駄でしょうから、Containerを停止します。
host$ docker-component stop
で停止,
host$ docker-component up -dで再開します。なお、containerを停止すると、Continerの起動中に作成したファイルは、
volumes
でホストのディレクトリに保存しているもの以外は全て消えてしまいます。containerのライフサイクル、データの永続化については以下のような記事を参考ください。
- https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32
- https://qiita.com/onokatio/items/fcc9f8f94f8533bb030aなお今回はホストのファイルシステムとの同期、という方法のみを扱っていますが、そのほかにも永続化手段もある模様(未トライ)
9. container, imageの削除
ニッチもさっちも行かなくなった場合、全ての過去を消し去りたいと思ったら、
docker-component down
コマンドを使います。下記が参考になります。気軽に環境丸ごと削除してやり直せるというのが、Dockerを用いた開発の最大のメリットでしょう。
以上です。