- 投稿日:2019-12-21T23:16:22+09:00
コンテナ内でcontainerdを動かす
この記事はDocker Advent Calendar 2019の21日目の記事です。
Dockerが内部で使用しているHigh-levelランタイムの
containerd
をコンテナ内で起動して動かしてみた話です。コンテナ内で動かす方法に関してはcontainerdのリポジトリにそのやり方が記載されていますが、その通りにやっても私の環境では一部上手くいかなかったのでその解決策も含めて紹介できればと思います。
環境
- OS: ubuntu 16.04
- golang: go1.13
- Docker: 19.03.5
- containerd: v1.3.0-203-g97712c8a 97712c8ad73dd302d5d226e0384b2d86e5de2989
ソースの取得
containerd
を動かすに当たってソースからバイナリを作成するのでローカルにソースを取得しておきます。
contaierd
の他にlow-levelランタイムであるrunc
も今回は一緒にビルドするので合わせて取得します。取得方法は
go get -u github.com/containerd/containerd
とgo get -u github.com/opencontainers/runc
を実行すればOKです。Dockerイメージの作成
ソースの取得が終わったら次に
containerd
を動かすコンテナのDockerイメージを作成します。
containerd
はGo言語を使用して作られているので、Dockerイメージのgolangをベースに、ビルドするのに必要なモジュールをインストールしていきます。
必要なモジュールはB-Tree FileSystem用のbtrfs-tools
とSeccomp用のlibseccomp-dev
の二つです。DockerfileFROM golang:latest RUN apt-get update \ && apt-get install -y btrfs-tools libseccomp-devあとは
docker build -t containerd/build .
でDockerイメージを作成すればコンテナ用のDockerイメージの準備は完了です。コンテナの起動
上記で作成したDockerイメージを使ってコンテナを起動します。
docker run -it --privileged \ -v /var/lib/containerd \ -v ${GOPATH}/src/github.com/opencontainers/runc:/go/src/github.com/opencontainers/runc \ -v ${GOPATH}/src/github.com/containerd/containerd:/go/src/github.com/containerd/containerd \ -e GOPATH=/go \ -w /go/src/github.com/containerd/containerd containerd/build bash
containerd
の起動には特権が必要になるので--privileged
オプションをつけ、起動に必要なフォルダと上記で取得したソースをマウントした上で起動しています。
そのほかのオプションはGOPATH
の設定とコンテナ起動時のディレクトリを指定しています。
公式のやり方ではbash
ではなくsh
を起動しているのですが、個人的にbash
の方が慣れているので変えています。ソースのビルド
次はコンテナ内で
containerd
とrunc
をビルドしていきます。
それぞれMakefile
が用意されているのでそれを利用します。// containerdのフォルダに移動。 // コンテナ起動時にこのフォルダがカレントディレクトリになっているはずなので実行しなくても大丈夫 $ cd /go/src/github.com/containerd/containerd $ make && make install // エラー! vendor/github.com/containerd/btrfs/btrfs.go:38:25: fatal error: btrfs/ioctl.h: No such file or directory #include <btrfs/ioctl.h> ^ compilation terminated. make: *** [bin/containerd] Erreur 2実はこの状態でビルドするとエラーとなります。
containerd
が依存しているcontaienrd/btrfs
というモジュールがあり、そのモジュールからbtrfs
がないと言われるのが原因です。Dockerイメージを作る際に
btrfs-tools
をインストールしましたが、どうもこれでは駄目なようでbtrfs-tools
の代わりにlibbtrfs-dev
をインストールすればビルドが通りました。DockerfileFROM golang:latest RUN apt-get update \ && apt-get install -y libbtrfs-dev libseccomp-dev公式に記載されているやり方と異なるので問題がある可能性もありますが、一旦これでDockerイメージを作成しなおしてコンテナを起動すればビルドは通るようになります。
あとは
containerd
と同様にrunc
もビルドしてやれば準備完了です。cd /go/src/github.com/opencontainers/runc make BUILDTAGS='seccomp apparmor' && make installcontainerdの起動
make install
した段階でcontainerd
のバイナリがPATH
の通っているディレクトリに配置されますのでそれを起動すればcontainerd
が動きます。$ containerd // バックグラウンドで起動したい場合は containerd & $ INFO[2019-12-21T13:56:32.716026618Z] starting containerd ... $ INFO[2019-12-21T13:56:32.760340925Z] loading plugin ... // 以下ログが出力されるこれでやっと
containerd
が動かせました!
あとは好きなようにいじりたおせばOKですね。まとめ
簡単ですがコンテナ内で
containerd
を動かすやり方を紹介させてもらいました。そもそも何故動かそうと思ったかというと、個人的にコンテナランタイムの開発に挑戦していて
Docker
で動かしてみたら上手く動かず原因を探っていくとcontainerd
とのやりとりに問題がありそうだという事が分かったので、containerd
を動かして見ようと思ったのがきっかけでした。ただ起動するだけでなく構成を記述した設定ファイルを渡す事もできるようなので、その辺りも公式に情報があるのでよければそちらも見てみて下さい。
参考
- 投稿日:2019-12-21T22:47:47+09:00
CentOS8のDockerイメージで送信専用SMTPサーバー
はじめに
以前投稿した「Dockerで送信専用メールサーバーなうに使っていいよ。」はCentOS7ベースのDockerイメージでした。
今回、CentOS8ベースに対応させたので記念投稿です。
https://hub.docker.com/r/takeyamajp/postfixCentOS7版からの変更点
- Microsoftなどビッグネームのトレンドに追従して証明書の暗号化レベルを引き上げました。
- postfixのバージョン変更に伴ってnewaliasesの整合性チェックが厳しくなっているので、警告が出ないように設定方法を変更しました。
- rsyslogのバージョン変更に伴って、docker向けの設定を変更しました。
- supervisorのバージョン変更に伴って、docker向けの設定を変更しました。
その他
今後centos8ベースのDockerfileを作る人に、rsyslogやsupervisorを使う場合の参考になればと思います。
知らない人は、必ずハマりますからね。Docker hubで星を付けて頂けると励みになります。
- 投稿日:2019-12-21T22:31:18+09:00
wardenを利用して Magento2ローカル開発環境を構築する
本記事は、Magento Advent Calendar 21日目の記事となります。
本記事では、巷で話題となっているMagentoローカル開発環境を容易に構築できる、WardenというCLIツールの使い方を紹介したいと思います。
既に実用的でかつ大変便利なツールではあるものの、最近ではAdobe Magento社のDeveloperからもプルリクエストが飛んでいるようで、現在進行形で爆速進化中といった様子です。
Wardenがやってくれること。
・SSLの終端制御とProxy/Routingによる、コンテナへのルーティング
・.testドメインに対するDNSレスポンス
・ローカル環境でのSSL証明書の発行
・Magento2インスタンスの構築仕組み
Wardenは下記の構成で管理されています。
メインのWarden用コンテナが4つ。 Magentoインスタンス用のコンテナが9つ。
◆メイン
・Dnsmasq ・・・ *.testドメインへの名前解決を担当。 (/etc/hostsを手動で変更する必要がなくなる)
・Traefik ・・・ アクセスされたドメイン名を元に、各MagentoインスタンスのVarnishコンテナにルーティング。
・Portainer ・・・ DockerコンテナをGUIから操作できる便利ツール (放置気味。。)
・Sshd ・・・ MysqlWorkBenchなどからコンテナにアクセスするための、SSHトンネル用コンテナ◆Magento(持て余すほどのフル構成)
- Varnish (ルーティング用にTraefie用のラベルが付けられている)
- Nginx (Cookieの値をみて、PHP-FPMを使い分ける設定がされている)
- PHP-FPM (n98-magerunが標準装備・Mailhogの設定済)
- PHP-FPM(Xdebug用)
- MariaDB (DockerHubの公式イメージ)
- Redis (Session・Cacheの保存用)
- ElasticSearch (検索・インデックス)
- RabbitMQ (非同期のメッセージングサービス)
- MailHog (メール送信テスト環境)
図にまとめてみるとこのような構成。
基本的な動き
ユーザからのhttpsアクセスに対して、dnsmasqコンテナでドメインの名前解決を行い、
Varnishに付与されているラベルを元に、traefikコンテナで各Magentoインスタンスへのリクエストのルーティングを行なっています。Magentoインスタンスをいくつ増やしても、traefikが自動的にコンテナの生成を検知し、リクエストのルーティングを行ってくれるため、前段のdnsmasq、traefikを一切管理しなくて良いのが良いところ。
xdebugの有効/無効の切り替えが容易
wardenでは、php-fpmコンテナを常時二つ稼働させており、片方はxdebugの設定がされています。
CookieにXDEBUG_SESSIONキーが挿入されていると、php-fpm(xdebug用)が使用されるようにnginxで制御されています。
Mailhogが捗る
デフォルトでPHP-FPMにMailhogの設定がされているため、Warden開発環境で送信されるメールは全てMailhogにプロキシーされます。
プロキシーされたメールは、https://mailhog.{project名}.test/ から確認可能。
使ってみるとこれがかなり便利。
wardenの使い方↓
使い方 (mac向け)
まずはwardenのインストールと起動。
$brew install davidalger/warden/warden $warden upwarden upコマンドで上記のメインとなる4コンテナが起動します。
$docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b4e8029d5655 jpillora/dnsmasq "webproc --config /e…" 23 hours ago Up 23 hours 127.0.0.1:53->53/udp dnsmasq 0030d07b863f traefik:v1.7 "/traefik --api --do…" 23 hours ago Up 20 hours 127.0.0.1:80->80/tcp, 127.0.0.1:443->443/tcp traefik e671dabdd02e portainer/portainer "/portainer" 23 hours ago Up 23 hours 9000/tcp portainer ede5a56b6fef panubo/sshd "/entry.sh /usr/sbin…" 23 hours ago Up 23 hours 127.0.0.1:2222->22/tcp tunnel正しく起動できていれば、下記URLでコンテナの稼働状況が確認できます。
Wardenの起動が完了したら、次はMagentoインスタンスを立ち上げていきます。
1.Magentoのソースコードが入ったディレクトリを作成
$composer create-project --repository-url=https://repo.magento.com/magento/project-community-edition magento22.環境設定の初期化: warden env-init [ProjectName] [EnvironmentType]
カレントディレクトリに、warden設定ファイルとなる.envが作成されます。warden env-init project magento2EnvironmentTypesは下記の3つがデフォルトで用意されています。(EnvironmentTypeは追加可能な様子)
- local
- Magento1
- Magento2
3.SSL証明書の作成・設定: warden sign-certificate [ProjectName].test
warden sign-certificate project.test4.Magentoインスタンスの起動
warden env up -d warden sync start5.コンテナが立ち上がったら、php-fpmコンテナに入ってMagentoのインストール
$warden shell (php-fpmコンテナに入る。⇩コンテナ内で実行) $bin/magento setup:install \ --backend-frontname=backend \ --amqp-host=rabbitmq \ --amqp-port=5672 \ --amqp-user=guest \ --amqp-password=guest \ --db-host=db \ --db-name=magento \ --db-user=magento \ --db-password=magento \ --http-cache-hosts=varnish:80 \ --session-save=redis \ --session-save-redis-host=redis \ --session-save-redis-port=6379 \ --session-save-redis-db=2 \ --session-save-redis-max-concurrency=20 \ --cache-backend=redis \ --cache-backend-redis-server=redis \ --cache-backend-redis-db=0 \ --cache-backend-redis-port=6379 \ --page-cache=redis \ --page-cache-redis-server=redis \ --page-cache-redis-db=1 \ --page-cache-redis-port=63796.各アプリケーションにアクセス
- (Magento フロント): https://app.project.test/
- (Magento 管理画面): https://app.project.test/backend/
- (MailHog 管理画面): https://mailhog.project.test/
- (Rabbitmq 管理画面): https://rabbitmq.project.test/
- (ElasticSearch 接続先): https://elasticsearch.project:.test/
7.Magentoインスタンスの破棄
$warden env down -v #コンテナ・ボリューム・ネットワークの削除 $warden sync stop #Mutagenセッションの終了使用感
MailhogやX-Debug切り替えなど、細かい開発支援機能が散りばめられており、かなり便利な印象。
ファイル共有にMutagenを使用しており、Docker for MacでもVagrant使用時と変わらない速度感。
EnvironmentTypeを新たに追加することで、独自のMagentoインスタンス用のコンテナ群を構築することが可能です。
今回は触れませんでしたが、使用するPHPやVarnishのバージョンを指定することも出来るようです。
また、プロジェクト毎に使用したいコンテナを差し替えるといったことも出来るようになっているので、柔軟な開発環境が構築できそうです。
おまけ
MysqlWorkbenchの設定方法
MysqlWorkbenchの設定方法が少し分かりずらかったので、念のため共有させて頂きます。
SSH Hostname: tunnel.warden.test:2222 SSh Username: user SSh Password: なし SSH Key File: $HOME/.warden/tunnel/ssh_key Mysql Hostname: project_db_1 (プロジェクトのdbコンテナ名) Mysql ServerPort:3306 Username : magento Password : magento
- 投稿日:2019-12-21T22:07:23+09:00
Visual Studio Code - "Remote Development" を使って Docker Container on "Vagrant + VirtualBox" のファイルを編集する
要約
- Vagrant で構築した仮想環境の中にある Docker へ繋げるときは 多段SSH を使う。
- Docker Container に SSHサーバ を構築する必要がある。
- VS Docde の Remote Development は Remote SSH を使用する。
はじめに
VS Code に Remote Development と呼ばれる拡張機能が追加されました。
数ヶ月遅れでその機能の素晴らしさに気づき、その活用方法をメモしておこうと記事を作成します。
基本的な用途は以下のクラスメソッドさんの記事が分かりやすいので参照ください。
【設定爆速】VS CodeのRemote Developmentを使ってSSH接続したEC2上のファイルを編集する
概要
書くこと
- VS Code Remote Development の活用方法
- 多段SSH を用いて、2つ先の仮想環境に繋げる方法
- docker container を作るポイント
- ホストOS の設定(
.ssh/config
)書かないこと
- Vagrant で Docker / docker-compose の環境を作る方法
想定環境
この記事で実現するシステムの構成は下図の通りです。
上図の通り、VS Code の Remote Development を使用して、リモート環境のコードを VS Code の UI で直接編集出来るようにします。
また、多段SSH の仕組みを用いて、1つ目の仮想環境の先に存在する Docker コンテナ に対しても同じ仕組みでコードの編集が出来るようにします。
今回の仕組みを実現した環境の詳細は以下の通りです。
Item Version HostOS Windows 10 VirtualBox 5.2.18 r124319 (Qt5.6.2) command> vagrant -v Vagrant 2.1.2 > vagrant plugin list vagrant-disksize (0.1.2) vagrant-docker-compose (1.5.1) vagrant-omnibus (1.5.0) vagrant-proxyconf (1.5.2) vagrant-vbguest (0.15.2) > vagrant box list centos/7 (virtualbox, 1905.1)command$ rpm -qa kernel\* | sort kernel-3.10.0-1062.9.1.el7.x86_64 kernel-3.10.0-957.12.2.el7.x86_64 kernel-devel-3.10.0-1062.9.1.el7.x86_64 kernel-headers-3.10.0-1062.9.1.el7.x86_64 kernel-tools-3.10.0-1062.9.1.el7.x86_64 kernel-tools-libs-3.10.0-1062.9.1.el7.x86_64Remote Development が実現すること
「ローカルPCのコードを修正して、それで十分?」
近年のソフトウェア開発の現状として、次のような傾向があります。
- 特定のコンテナやVMでのみでアプリケーションが動作する。
- ローカルでは実現出来ない実行環境が多くある。
こういった現状の中で、ローカルPCでソースコードのみ修正出来たとしても、以下のようなケースにおいては、手間が増えてしまいます。
- 実行環境へのデプロイが必要である。
- IDEが直接コードを実行することで実現出来るようや動的解析機能のため、ローカルPCにも開発キットの導入が必要なケースがある。
例えば次の図のように、コンテナ上に PHP の実行環境を作って動作出来るようにした場合を考えます。
コンテナ上のアプリケーションは意図した通りに動くでしょうが、 VS Code で静的解析や動的解析を行いたい場合、別途、Host OS や ローカルPC上の VS Code に手を加える必要が出てきます。また、Web Application をチーム開発する場合には、Docker などで共通化した仮想環境を作成して配布することが多いと思いますが、ローカルPCで別途設定が必要となると、全てが共通化出来ているとは言えず、面倒な手間も増えてしまいます。
リモート環境のコンテクストで、リッチなローカル開発環境の提供
VS Code の Remote Development を使用することで ローカルPC 上の VS Code を使用して、リモート環境にあるコードを違和感なく編集することが出来ます。
cited from Remote Development with VS Code - Visual Studio Code3つの拡張機能
Remote Development は、次の3つリモート環境に対応しています。
- remote workspaces running in WSL
- remote workspaces running in Docker containers
- remote workspaces running in physical and virtual machines over SSH
cited from Remote Development with VS Code - Visual Studio CodeArchitecture and extension
Remote Development は、大きく別けて以下の2つの extension から構成されています。
- UI Extensions
- Workspace Extensions
この2つは、下図のようなアーキテクチャで構成されています。
cited from Supporting Remote Development and Visual Studio Online - Visual Studio Code実現のイメージ
今回の記事では、次のように、ホストOS の VS Code から 仮想環境のコードを編集出来るようにすることを目指します。
特に、仮想環境の上にある Docker Container を、同じ仕組みでどのように実現するかがポイントです。設定手順
設定を行うにあたって、 Docker や docker-compose の導入以外で特徴的な作業としては次の3つがあります。
- Docker Container に sshd サーバを構築し、 root ユーザでログイン出来るようにする。
- Docker Container 起動時に Port Forward 設定を行う。
- Host OS に
ssh/config
設定を追加する。これらを図で示すと以下のようになります。
この設定を行うことで、 HostOS に存在する VS Code の Remote Development を使用して、2つ先の Docker Container に対して Remote SSH 接続を行うことが出来ます。
1. Vagrant 環境の構築
まず最初に、 Docker と docker-compose をインストールした 仮想環境を構築します。
この手順は本筋ではないので、次の手順で構築してください。
(設定内容は anfangd/docker-on-vagrant-script - GitHub を参照ください。)command(powershell)## Vagrant のプラグインをインストールする > vagrant plugin install vagrant-vbguest > vagrant plugin install vagrant-proxyconf ## GitHub から Vagrantfile と provision.sh を取得する > git clone https://github.com/anfangd/docker-on-vagrant-script.git > cd docker-on-vagrant-script ## Vagrant の起動する > vagrant upvbguest に関連するエラーが発生した場合は以下を参照してください。
(kernel version のミスマッチによってエラーが発生する可能性があります。)2.
.ssh/config
の設定(その1)次のコマンドで、Vagrant で起動している仮想環境の ssh-config を確認することが出来ます。
command(powershell@Windows10)> vagrant ssh-config Host default HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key IdentitiesOnly yes LogLevel FATAL上記のコマンドで確認した内容を、
.ssh/config
にコピペします。
なお、Host名は任意の名前に変更してください。これらは Windows 10 向けの設定のため、macOS などの場合は適宜 PATH の修正などを行ってください。
.ssh/config(Windows10)Host vagrant-os HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key IdentitiesOnly yes LogLevel FATAL3. 秘密鍵の転送
Guest OS から Docker に接続するために、 Vagrant が自動生成した 公開鍵のペアを使用します。
Host OS 上に秘密鍵が存在するので、 Guest OS へ秘密鍵をコピーします。command(powershell@Windows10)## 注意 `vagrant up` したディレクトリで実行する > scp .vagrant/machines/default/virtualbox/private_key vagrant-os:/home/vagrant/.ssh/ ## Guest OS に SSH接続 > vagrant ssh ## private_key の実行権限を変更(Guest OS 内) $ chmod 600 ~/.ssh/private_key4. Docker Container の起動
Docker を実行出来る仮想環境の構築が出来たら、 Docker Container を構築します。
以下は今回使用する Dockerfile です。Dockerfile# image FROM php:7.0.15-fpm ENV LANG C.UTF-8 RUN apt-get update -qq && \ apt-get install -y \ zlib1g-dev \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-install zip \ && yes "" | pecl install xdebug \ && docker-php-ext-enable xdebug \ && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd RUN apt-get update \ && apt-get install -y libpq-dev \ && docker-php-ext-install pdo_mysql pdo_pgsql RUN apt-get update \ && apt-get install -my wget gnupg WORKDIR /opt/ # ここから最後までがポイント RUN apt-get update && apt-get install -y openssh-server RUN mkdir /var/run/sshd ## /etc/ssh/sshd_config の設定書き換え RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config # SSH login fix. Otherwise user is kicked off after login RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd ENV NOTVISIBLE "in users profile" RUN echo "export VISIBLE=now" >> /etc/profile # 公開鍵をコピー COPY authorized_keys /root/authorized_keys EXPOSE 22 # Activate authorized_keys & Boot sshd CMD mkdir ~/.ssh && \ mv ~/authorized_keys ~/.ssh/authorized_keys && \ chmod 0600 ~/.ssh/authorized_keys && \ # 最後に ssh を起動 /usr/sbin/sshd -D上の Dockerfile のうち、後半部分で openssh-server の導入や 公開鍵認証の設定などについて記載しています。
Docker Container の起動は次のコマンドで実行します。
command(bash@CentOS)$ pwd /vagrant/docker-sample # 公開鍵をコピー $ cp ~/.ssh/authorized_keys . $ ls Dockerfile authorized_keys # build $ docker build ./ -t example # Docker Container を起動 # Port:10000 を Port:22 に転送 $ docker run -d -p 10000:22 example # Docker Container に SSH 接続 $ ssh root@127.0.0.1 -p 10000 -i ~/.ssh/private_key5.
.ssh/config
の設定(その2)2.) で設定した
.ssh/config
に設定を追加します。.ssh/config(Windows10)Host vagrant-os HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key IdentitiesOnly yes LogLevel FATAL # 以下を追加 Host docker-os Hostname 127.0.0.1 User root Port 10000 ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p vagrant-os IdentityFile C:/Users/<username>/work/vagrant/centos-7-docker/.vagrant/machines/default/virtualbox/private_key上記の設定で Docker Container に接続出来るか確認してみましょう。
command(powershell@HostOS)> ssh docker-osこれで接続できれば設定は完了です。
6. Visual Studio Code の設定
前節までの設定が出来てしまえば、あとは以下の記事の通り extensions をインストールして開けば使用出来ます。
以下のように、CentOS へのアクセスを示す
vagrant-os
に加え、その上の Docker Container であるdocker-os
も開けるようになっています。extra-1. 【HostOS←→GuestOS】 のフォルダ同期を停止する
Vagrant で構築した GuestOS のフォルダと HostOS のフォルダを同期する方法は、非常に便利なようで厄介な点がいくつかあります。
私は以下のような事象で時間を取られることがよくあります。
- Vagrant や Box のバージョンアップで頻繁にエラーが発生する。
- GuestOS 内の Webサーバと通信する時、HTTP アクセスが遅くなる。
npm install
する時にエラーが発生する。ただ、今回の記事で使用した VS Code - Remote Development を使用すれば、ファイル同期の必要がなく、仮想環境内のファイルを直接修正出来るのでこのファイル同期の仕組みが不要になります。
同期をしないようにするには、以下のように Vagrantfile を修正して
vagrant reload
すれば良いだけなので非常に簡単です。Vagrantfile(@HostOS)<略> # Synced Folder #config.vm.synced_folder "./", "/vagrant", type:"virtualbox", mount_options: ['dmode=777','fmode=777'] config.vm.synced_folder ".", "/vagrant", disabled: true <略>一方で、これをしてしまうと、これまで当たり前に出来ていたことが一部できなくなってしまいます。
想定されるケースと対策で重要そうなものを以下に記載します。
- GuestOS にファイルを配置する。
→scp コマンドなどで転送する。- 仮想環境と同期しているフォルダの git リポジトリを Sourcetree で参照していた場合の対処法
→VSCode の拡張機能で代替する。- Vagrant の Box を誤って削除してしまう。
→HostOSとファイル同期してないので、中身は消えてしまいます。
こまめに commit & push して、Vagrant Box の環境は削除される前提で作業しましょう。おわりに
多段SSH方式、めちゃくちゃ便利ですね。
Remote Container で実現する方法を模索して時間を浪費してしまったのですが、多段SSH方式でスムーズに実現することが出来ました。そして何より、 Visual Studio Code さん、どんどん使いやすさが増してゆきます。
TODO
活用方法について記事作成(PHP Xdebug の導入など)
→書きました:Visual Studio Code - Remote Development を使用して PHP Xdebug を使ったデバッグを行う #Qiita参考
Vagrant + VirtualBox で Docker 環境を構築する。
Vagrant で共有フォルダ設定でエラーが出来た時の対処法
※ Remote Development 機能の出現によって、この共有をしない方が開発が効率的になる可能性有り。
多段SSHの実現方法
- 投稿日:2019-12-21T21:04:14+09:00
corcelを使ってdockerコンテナ間でlaravelからwordpressのDBに接続する
corcelの事前設定
下記を参考に進めていきます。
かなり巻いてます(師走だからね)。https://github.com/corcel/corcel
まずはcorcelをインストール
composer require jgrossi/corcellaravelのバージョンが5.4以下は下記を記載
config/app.php'providers' => [ /* * Package Service Providers... */ Corcel\Laravel\CorcelServiceProvider::class, ]php artisan vendor:publish --provider="Corcel\Laravel\CorcelServiceProvider"databaseにwordpressの接続設定を記載。
config/database.php'wordpress' => [ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'mydatabase', 'username' => 'admin', 'password' => 'secret', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => 'wp_', 'strict' => false, 'engine' => null, ],コネクションを'wordpress'へ変更
config/corcel.php<?php return [ (省略) 'connection' => 'wordpress', (省略) ];WpPostモデルを作成します。
php artisan make:model WpPostWpPost.php<?php namespace App; use Illuminate\Database\Eloquent\Model; use Corcel\Model\Post as Corcel; class WpPost extends Corcel{ protected $connection = 'wordpress'; }wordpressとlaravelのdockerの設定
事前に作成済みのwordpressのdocker-compose.ymlファイルの末尾に下記を記述
wordpress側docker-compose.ymlnetworks: default: external: name: new_networklaravel側docker-compose.ymlnetworks: default: external: name: new_networkcreateコマンドでnew_networkを作ります。
docker network create new_networkdocker networkコマンドで確認します。
docker network ls xxxxxxxxxx my_network bridge localdockerコンテナを立ち上げます。
docker-compose uplaravel側のdatabase設定を修正
dockerコンテナ内のwordpress-mysqlにログインし、アドレスを確認します。
hostname -i 192.168.1.2laravelのdatabase.phpの設定内容を変更します。
それぞれwordpressのwp-config.phpの設定を元に書き換えていってください。config/database.php'wordpress' => [ 'driver' => 'mysql', 'host' => 192.168.1.2, 'database' => 'mydatabase', 'username' => 'wordress_root', 'password' => 'wordpress_password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => 'wp_', 'strict' => false, 'engine' => null, ],wordpressのDBに接続
laravelのdockerコンテナにログインし、wordpressのDBに接続します。
php artisan tinker >>> App\WpPost::find(1) => App\WpPost {#5963 ID: 1, post_author: 1, post_date: "2017-10-20 12:06:00", post_date_gmt: "2017-10-20 03:06:00", post_content: "WordPress へようこそ。これは最初の投稿です。編集もしくは削除してブログを始めてください !", post_title: "Hello world!", post_excerpt: "", post_status: "publish", comment_status: "open", ping_status: "open", post_password: "", post_name: "hello-world", to_ping: "", pinged: "", post_modified: "2017-10-20 12:06:00", post_modified_gmt: "2017-10-20 03:06:00", post_content_filtered: "", post_parent: 0, guid: "http://localhost:8888/?p=1", menu_order: 0, post_type: "post", post_mime_type: "", comment_count: 1, meta: Corcel\Model\Collection\MetaCollection {#5964 all: [], }, }無事接続できました!!
- 投稿日:2019-12-21T20:53:20+09:00
mong - Dockerのコンテナ名をランダム生成するコードをPythonに移植してみた -
goofy_grothendieck
,ecstatic_lederberg
,quizzical_wu
, ...
Dockerのコンテナのように,ランダムなんだけど読みやすい名前を付けたいことってありますよね?moby/mobyにGo言語のコードを見つけたのでPythonに移植してmongというライブラリにしてみました.2019/12/22追記: 続報書きました
使い方
Python 3.6と3.8で動作確認しています.Python3.5以降なら動くと思いますが,Python2はType Hintingなどが原因で動きません.
標準ライブラリだけしか使っていないので,インストールはすぐ終わるはずです.
$ pip install git+https://github.com/toshihikoyanase/mong.gitさっそく,ランダムに名前を生成してみましょう.
(2019/12/22修正: インスタンス化する方法から関数呼び出しに変更しました)
import mong mong.get_random_name() # 'goofy_robinson' mong.get_random_name() # 'stoic_feynman'Google ColabにJupyter Notebookを用意しました.以下からすぐに試せます:
実装方針
オリジナルのコードを見ると名前の元となる単語の辞書がその大半をしめていました.移植先のコードに辞書をべた書きすると,メンテナンスが大変そうなので,オリジナルのコードから抽出する方法を選びました.
具体的には下記のとおりです.
-mong/create_dict.py
でオリジナルのコードから名前のもととなる単語の辞書を抽出しています.
-mong/moby_dict.json
に抽出した辞書を保存しています.
-mong/name_generator.py
のNameGenerator
に名前生成ロジックを移植しています.オリジナルの実装
Dockerの名前生成コードは moby/moby にあって,Go言語で書かれています.なお,mobyはコンテナシステムのためのツール集のようです.こちらのスライドに簡潔にまとめられています.
名前は2つの語からなっていて,形容詞と有名な科学者とハッカーの人名です.それらが
_
でつながれています.例
# 怒った(形容詞)_チューリング(人名) angry_turing形容詞は
left
,人名はright
というリストで管理されています.left = [...]string{ "admiring", "adoring", "affectionate", "agitated",right = [...]string{ // Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. https://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB "albattani", // Frances E. Allen, became the first female IBM Fellow in 1989. In 2006, she became the first female recipient of the ACM's Turing Award. https://en.wikipedia.org/wiki/Frances_E._Allen "allen",名前の生成処理は,基本的にランダムに選択して,つなぐだけです.
// GetRandomName generates a random name from the list of adjectives and surnames in this package // formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random // integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3` func GetRandomName(retry int) string { begin: name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))]) if name == "boring_wozniak" /* Steve Wozniak is not boring */ { goto begin } if retry > 0 { name = fmt.Sprintf("%s%d", name, rand.Intn(10)) } return name }このQiita記事にもあるように,
boring_wozniak
は生成されないようになっています.(出たらもう一度作り直しています.)2019年12月21日時点で,
left
は108語,right
は235語あったので合わせて25,379種類の名前が生成できます.意外と少ないような気がしますね.なお,
retry
引数についてはよくわかっていなくて,処理を見てもretry
しているように見えません.retry>0
だと0
以上9
以下の整数をランダムに選んで名前の末尾につけています.これは使う側のコードを読まないとわからないかもしれません.単純に1桁種類数を増やすためかな?まとめと今後の課題
PythonでDockerコンテナ風のランダム名を生成できる mong というライブラリを作ってみました.
一応,動くところまでは書いたのですが,テストカバレッジが低かったり,エラー処理を省いていたり,CIをしていないなどいろいろ改善の余地はあります.また,pypiに登録していないので,インストールがやや面倒です.
(自分も含めて)ニーズがあればもう少し整えようかなと思っています.
参考文献
- 投稿日:2019-12-21T20:00:27+09:00
オレオレGyazoでスクショを瞬間共有
はじめに
Gyazoというアプリケーションをご存知でしょうか。
「スクリーンショットの瞬間共有」というキャッチフレーズで、世界中で使われているハイパー売れっこアプリなため、もしかすると知らない人の方が少ないかもしれません。↑このように、Gyazoのクライアントアプリを起動して範囲を選択すると、スクリーンショットが撮られてすぐにGyazoのサーバーにアップロードされます。
その後URLが返却され、ブラウザが開きすぐにアップロードされたスクリーンショットを確認することができ、他の人に共有する際はこのURLを共有するだけです。通常スクリーンショットを共有しようとすると、撮る→端末に保存→アップロードといった流れになると思うと、非常に簡単に済みますね。
また、例えば表形式の資料で画像もつけたいといった場合でも、下記のように画像URLを貼り付けておくことで良い感じに収めることができます。この手軽さ便利さから、前に働いていた職場では非常に流行っており、あちこちから「ごめん、それちょっとGyazoってくんね」だとか「すぐにGyazoって送ります」「お前も結構Gyazoってきたね」だとか、とにかく「Gyazoる」という単語が飛び交っており、最終的にはただスマホで写真を撮る時にさえGyazoるとか言ってたくらいには中毒者が続出していました。
これに関しては、人によっては口に出すとちょっと気持ち良い響きなのが原因なのかもしれません。問題点
ただ、このGyazo、無料で使おうとすると少し問題があります。
1 広告が結構邪魔
2 アップロードした画像は一般公開される
3 キャプチャしたものが一覧で見られる画面があるが、直近10件まで上記の問題は有料版にすることで解決することができますが、お金を払ってGyazoライフを送れるようなイカした人はお洒落なオフィスで可愛いあの子とネスカフェアンバサー出来るような人間だと相場は決まっています。
私のように、会社に在籍する猫たちの飲み水をこっそり盗み飲むような人間には、中々真似することはできません。有料版にせずとも、Gyazoサーバーを社内サーバー等に構築することでも解決が可能です。
これはオレオレGyazoとかいって、割と有名らしいです。
Gyazoはサーバー、クライアントと2つのアプリケーションで動いているのですが、実は両方ともソースコードが公開されています。
サーバー側はRubyで書かれているCGIスクリプトを少し変更して配置すれば良く、クライアント側はmacであればスクリプトを少し弄るだけでオレオレGyazoの環境は完成します。ちなみに
キャプチャしたものが一覧で見られる画面があるが、直近10件まで
こちらの問題に関してですが、オレオレGyazoだと公式と違ってそもそも一覧画面がありません。
ただ、画像は自分のサーバーに置かれるため、一覧画面など欲しい機能は自作することで好きなように対応することができます。オレオレGyazoのやり方は調べれば割と色々出てきますが、基本的に流れとしては
apacheをインストール→サーバーのスクリプトを取ってきて配置といった流れになるかと思います
試しにEC2に作ってみると、思いの外あっさりと出来てしまいました。
同じようにやり方を書くのもつまらないと思ったため、今回はEC2で行った流れを元にDocker化し、ローカルやら他の環境でもパパッとビルドしてシュルっと試せるようにしてみました。サーバー側用意
サーバー側の動作としては、クライアントから送信されてきた画像を保存し、そのURLを返すというシンプルなものになっております。
とりあえずローカルで動くように書いたDockerfileが下記となります。FROM centos:centos7 #諸々インストール RUN yum update -y && yum clean all \ && yum -y install ruby \ && yum -y install wget \ && yum install -y httpd && yum clean all #適当になんか入れとく RUN echo "I was the god of Gyazo" > /var/www/html/index.html #gyazoサーバースクリプト等配置 WORKDIR /var/www/cgi-bin/ RUN wget https://raw.github.com/gyazo/Gyazo/master/Server/upload.cgi \ && chmod +x upload.cgi WORKDIR /var/www/ RUN mkdir cgi-bin/db \ && mkdir html/data \ && chmod 777 cgi-bin/db \ && chmod 777 html/data #ファイルをちょこっと書き換える RUN sed -i -e "s/#AddHandler cgi-script/AddHandler cgi-script/" /etc/httpd/conf/httpd.conf WORKDIR /var/www/cgi-bin/ RUN sed -i -e "s/usr\/bin\/env ruby/usr\/bin\/ruby/" upload.cgi \ && sed -i -e "s/data\/#{hash}.png/..\/html\/data\/#{hash}.png/" upload.cgi \ && sed -i -e "s/gyazo.com/localhost\/data/" upload.cgi RUN systemctl enable httpd EXPOSE 80dockerの入った環境で、どこでも良いので上記ファイルを置き、ビルドします↓
docker build --rm -t gyazo .gyazoという名前でイメージができました。
これを起動します。docker run -d --privileged --name gyazo -i -t -p 80:80 gyazo /sbin/initこれでサーバーが立ち上がります。
ブラウザから http://localhost/ にアクセスてしてみて、「I was the god of Gyazo」とか出ていたら成功です。
これでサーバー側は完成です。
立ち上がっていなかったら・・・ちょっとよく分かりません。
コンテナとかイメージを削除して再ビルドとかしてみたら上手くいくんじゃないでしょーか。クライアント側用意
続いて、クライアント側の用意をします。
MacとWindowsでやり方が違うのですが、私はMacでしか試していないためここではMacのやり方を載せます。
Windowsのやり方は、「Gyazo 自分のサーバーで」等で検索してみたりで探してみてください。(少し情報が古いものが多いため、ちゃんと動作するかは分かりません)
Macだとクライアントはシェルスクリプトで書かれているらしく、直接アップロード先等を書き換えるだけで良いようです。クライアントアプリ自体はホームページからダウンロード、インストールします。
こちらからダウンロードします。
https://gyazo.com/その後、
/Applications/Gyazo.app/Contents/Resources/
にあるscriptというファイルを開き、送信先の設定である下記の2点を書き換えます。HOST = 'upload.gyazo.com' ↓ HOST = 'localhost'CGI = '/upload.cgi' ↓ CGI = '/cgi-bin/upload.cgi'さらに、Gyazoはある時からデフォルトだとhttpsで通信を利用するようになっているらしいです。
そのためサーバー側にSSLの証明書の設置が必要となりますが、とりあえず動かしたいので、その辺もスクリプトを弄って何とかします。PORT = 443 ↓ PORT = 80※ポートに関しては、dockerコンテナ立ち上げ時に違うポート番号で立ち上げている場合は、そのポート番号を指定します。
http.use_ssl = true ↓ http.use_ssl = falseこれで動くようになりました。
邪魔な広告がないのと、本家と比べるとだいぶ動作が軽くなりました。おそらく余分なスクリプト等が走っていないためだと思われます。正直、個人的にはこれがオレオレGyazoで一番嬉しい所です。
試しにEC2インスタンスでやってみても動きました。Dockerなので他の環境でも多分問題ないはず。これによって一瞬でスクリーンショットを共有することで、非常にスマートな印象を与えられます。気になるあの子に披露して見せたら、感涙に咽びながらクリスマスを共に過ごしてくれること間違いなしです。
ただ、apacheでCGIを動かして〜といったことは少々古めかしいらしく、最近だとサーバーレスとかでやったほうがナウいっぽいみたいです。(ナウいはダサいの対義語です)皆様も今日から素敵なGyazoライフをお過ごし下さいませ。
- 投稿日:2019-12-21T18:18:02+09:00
Docker setting のShared Drivesでエラーが出たときの対処法
概要
DockerのShared DriveでDドライブを指定したら
FireWallのエラーが出たので、その時の対処方法を載せます。環境
OS : Windows10 pro (64bit)
セキュリティソフト: Norton(ノートン)エラーメッセージ
Firewall detectedということでファイアウォールに引っかかってしまった模様。
公式Help
10.0.75.1 on port 445 (the Windows host) from 10.0.75.2 (the virtual machine)
という事なので、Windows10 pro 以外の方はipアドレスを[10.0.75.2]に読み替えて実施してください。
対処法
まずはNortonのファイアウォール設定を開きます。
手順1 : [設定] > [ファイアウォール] >[トラフィックルール]
手順2 : [追加する]をクリック
手順3 : [許可] にチェックを入れて[次へ]
手順4 : [その他のコンピュータからの接続]にチェックをいれて[次へ]
手順5 : [下記のリストにあるコンピュータとサイトのみ] にチェックを入れて[追加する]をクリック
手順6 : [ネットワークアドレスを使う] にチェックをいれて、以下の内容で[OK]
手順7 : 以下の設定をして[追加する]をクリック
- 許可したいプロトコル: TCP
- どの種類の通信またはポートを許可しますか: [下記のリストにあるすべてのポートに一致する場合のみルールを適用する]
手順10 : 特に変更しないで[次へ]をクリック
(ログを残したい場合はチェックを入れて[次へ])
手順13: 追加されたルールを上に移動する
※ 遮断ルールより上に移動
備考
取り急ぎの対応ですが、とりあえずエラーメッセージは出なくなりました。
今後もFirewall関連の問題が出てきたらここの記事に追加していきたいと思います。
- 投稿日:2019-12-21T17:58:19+09:00
【venv不要】Remote Containersで作る最強のPython開発環境【VSCode/Docker】
はじめに
人気言語Top1に輝いたり1、IPA 基本情報技術者試験の試験科目になる2などして注目を集めているPython。
でもちょっと待って!あなたはPythonのエコシステムの恩恵を正しく受けて開発できていますか?
開発環境をうまく作ることで、 入力補間やフォーマッターによって開発が効率化されるだけでなく静的解析によって予期せぬ不具合を未然に防ぐことができ、①簡単 ②爆速 ③安全 にプログラムを書くことができます。
もちろんそのような快適な環境を作るためのHow to記事はたくさんありますが、問題はせっかくオレオレPython開発環境を作れたとしても、それを異なるPC間で共有するのが困難であるということです。
なぜなら、
- Pythonやpipで入れるモジュールのバージョンを揃えてインストールしないといけない
- fommter / linter / IDEの拡張機能を揃えてインストール&設定しないといけない
という、開発環境に依存する問題が発生するからです。
個人 / 複数人を問わず、異なるPC間であっても同一の動作をすることが保証されて欲しい。
かつ、 テキストエディタでプロジェクトを開くだけで、その開発環境が勝手に構築されて欲しいという要求があります。ということで、この記事では、VSCodeのRemote Containerを使うことでこの問題を解決します。
本記事で述べる方法を用いると、以下のようなことが実現されます。
- Win / Mac / Linuxを問わず、全ての環境で同一の動作をすることが保証される3、ポータブルなPython開発環境が作れる
- 新しい環境でも、プロジェクトを開いただけで静的解析や自動フォーマットなどの全ての設定が完了する
では、やっていきましょう
インストール
本記事では、以下のツールを用います。
他の記事を参考にしながらインストールしてください。
- VSCode
- Docker
ターミナルから以下のコマンドが打てれば準備完了です。
$ docker --version Docker version 19.03.5, build 633a0eaRemote Containersの設定
まずは、開発用のディレクトリを適当に作りVSCodeで開きましょう。
$ mkdir python-test以下のようなディレクトリ構成を作ります
. └── python-test ├── .devcontainer │ ├── Dockerfile │ └── devcontainer.json ├── .vscode │ └── extensions.json └── src └── main.pyそれぞれのファイルには以下の内容をコピペしてください。
.devcontainer/DockerfileFROM python:3.7.3-slim RUN apt-get update \ && apt-get install -y --no-install-recommends \ apt-utils \ gcc \ build-essential \ && pip install --no-cache-dir \ autopep8 \ flake8 \ && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/*ここで、
FROM python:3.7.3-slim
の部分の数字を変えると、好きなPythonのバージョンを指定することができます。.devcontainer/devcontainer.json{ "name": "Python Project", "dockerFile": "Dockerfile", "settings": { "terminal.integrated.shell.linux": "/bin/bash", "python.pythonPath": "/usr/local/bin/python" }, "extensions": [ "ms-python.python" ] }ここで、
"name": "Python Project"
の部分は好きな文字列にしてしまって構いません。
settings
には、.vscode/settins.json
で書くものと同一のものを記述することができます。本来bashのパスやpythonのパスは環境依存であるため個人ごとに設定する必要があるのですが、今回はコンテナ内で実行されるのでパスの情報が既知であり、固定することができるというのがポイントです。また、
extensions
には、VSCodeの拡張機能を加えることができ、ここに記述した拡張機能は自動でインストールされます。VSCodeの拡張機能を強制的にインストールさせることができるのはRemote Containersならではなので、全員にインストールして欲しい拡張機能はここに書きましょう。今回はVSCode用のPython拡張機能を追加しています。src/main.pyimport sys print(sys.version_info)Pythonスクリプトはバージョンを出力するものとでもしておきましょう。
.vscode/extensions.json{ "recommendations": [ "ms-vscode-remote.remote-containers" ] }VSCodeの拡張機能のRecommendationsにRemote Containersを指定します。
注意しなければならないのはdevcontainer.json
内のextensionsと違って、記述しても実際にインストールされるわけではありません。ですので、ファイルをコピペし終わったら実際にインストールするためにVSCodeを開き直してください。
すると、右下に以下のようなポップアップが出てくると思います。Install Allを選び、Remote Containerをインストールしましょう。
無事、インストールできたらVSCodeの左下に緑色のボタンが表示されます。
「Remote-Containers: Open Folder in Container...」を選びます。
フォルダ選択画面がでたら、プロジェクトのディレクトリ(今回の場合はpython-test)を選びましょう。すると
.devcontainer/Dockerfile
に記述したコンテナのビルドが自動で走ります。detailsを開くことで 経過を見ることができます。もしbuildにこけてしまった場合もdetailsを見ましょう。
ビルドが正常に終わったらそのままコンテナを起動し接続してくれます。コンテナに接続されたらVSCodeの内部ターミナルを開いてください。
おや?なにやらシェルのユーザーがrootになっていて、ディレクトリも
/workspaces
になっていますね。これは、ホストOS(Win / Macとか) のターミナルではなく、ホストOSから独立したコンテナのターミナルに入れていることを示しています。Docker分かんないよ!という方もいるかもしれませんが、とりあえずPythonを実行してみましょう。
/workspaces/python-test# python src/main.py sys.version_info(major=3, minor=7, micro=3, releaselevel='final', serial=0)
FROM python:3.7.3-slim
で指定したバージョンのpythonが入っていますね!
これで基本的な設定は完了です。今後は他のPCで
git clone
しても、「Remote-Containers: Open Folder in Container...」でコンテナの中に入ることで、同一の環境を再現することができます。requirements.txtの設定
ここはコンテナの中なので、この中で好きに
pip install
しても構いません。ここでインストールしたモジュールはホストOSにはまったく影響を与えることがないので、破壊的に開発を進めることができます。/workspaces/python-test# pip install numpy /workspaces/python-test# python >>> import numpy as np >>> np.__version__ '1.17.4'また、再度コンテナをビルドして作り直すとインストールしたモジュールは消えます。そこで、開発を進める中でこのpipモジュールはfixしよう!となった場合、Pythonで慣例として使われている
requirements.txt
を作って、そこにpip install
するモジュールを書くこととしましょう。ディレクトリ構成と
requirements.txt
の書き方は以下の通りです。. └── python-test ├── .devcontainer │ ├── Dockerfile │ └── devcontainer.json ├── .vscode │ └── extensions.json └── requirements.txtrequirements.txtnumpy==1.17.4requirements.txtには、
pip install
する際のバージョンを固定して書くことができます。再現性を担保するために、バージョンは固定することが望ましいです。そして、
devcontainer.json
を以下のようにしましょう。.devcontainer/devcontainer.json{ "name": "Python Project", "dockerFile": "Dockerfile", "settings": { "terminal.integrated.shell.linux": "/bin/bash", "python.pythonPath": "/usr/local/bin/python" }, "extensions": [ "ms-python.python" ], "postCreateCommand": "pip install -r requirements.txt" }
postCreateCommand
というのが追加されましたね。これは、コンテナが生成された後に実行するコマンドです。今後はrequirements.txt
に記述したモジュールが必ずインストールされます。ファイルを更新したら、更新をコンテナに反映させるために、左下の緑色のボタンを押して、「Remote-Containers: Rebuild Container」を選びましょう。
formatter / linterを設定する
続いて、formatter / linterを設定していきます。
pythonのformatter / linterを追加したときのdevcontainer.json
は以下のとおりです。.devcontainer/devcontainer.json{ "name": "Python Project", "dockerFile": "Dockerfile", "settings": { "terminal.integrated.shell.linux": "/bin/bash", "python.pythonPath": "/usr/local/bin/python", "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": true, "python.linting.flake8Args": [ "--ignore=E402,E501" ], "python.formatting.provider": "autopep8", "python.formatting.autopep8Args": [ "--ignore", "E402,E501", "--max-line-length", "150" ], "[python]": { "editor.formatOnSave": true } }, "extensions": [ "ms-python.python" ], "postCreateCommand": "pip install -r requirements.txt", }linterとしてflake8、 formatterとしてautopep8を指定し、それぞれE402(Module level import not at top of file)とE501(Line too long)を無視しています。ファイルのセーブ時にformatがかかるようにしています。
これでこんなふうなめちゃくちゃなコードを書いても、
before.pya =0 def method1(args) : print( args) def method2() : if a ==0: method1( "hoge" + "fuga" )このように、保存する際に整形してくれます。
after.pya = 0 def method1(args): print(args) def method2(): if a == 0: method1("hoge" + "fuga")通常、このようなformatter / linterの設定は
.vscode/settings.json
に記述します。しかし、.vscode/settings.json
は個人の設定ファイルであるから、.gitignore
に設定しているプロジェクトも多いです。加えて、pip install flake8 autopep8
を手動で実行する必要があるので、設定ファイルを書いたからといって、formatter / linterが適用されるわけではありません。一方で、今回はRemote Containersの設定ファイルに書くことができるので、共有もしやすいですし、確実にflake8やautopep8が入っている状態を再現できるので "フォーマットがかかっていないソースコードがコミットされる"ということも防ぐことができます。
ところで、
pip install flake8 autopep8
はどこで実行していたのでしょうか?
答えは.devcontainer/Dockerfile
の中にあります。.devcontainer/DockerfileFROM python:3.7.3-slim RUN apt-get update \ && apt-get install -y --no-install-recommends \ apt-utils \ gcc \ build-essential \ && pip install --no-cache-dir \ autopep8 \ flake8 \ && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/*もしあなたが、コンテナ内で
pytest
を記述したいと思った場合は追加することができます。.devcontainer/DockerfileRUN pip install --no-cache-dir \ autopep8 \ flake8 \ pytestまた、autopep8やflake8は開発時に必要なのであって、実行時には不要です。そうしたモジュールはDockerfileに書いて、実行時に必要なファイルは
requirements.txt
に書く、という使い分けができます。静的型解析
最後にPython3.6以降4で使えるType Hintsを導入しましょう。Type Hintsを導入することで、QoLが爆上がりします。
devcontainer.json
を以下のようにしましょう
ここでは、Type Hintsの静的解析ツールとして、pyrightを用います。.devcontainer/devcontainer.json"extensions": [ "ms-python.python", "ms-pyright.pyright" ],変更したら、左下の緑色のボタンを押して、「Remote-Containers: Rebuild Container」を選びましょう。
続いて、pyrightの設定ファイルを書きます。
ディレクトリ構成は以下の通りです。. └── python-test ├── pyrightconfig.json └── src └── main.pypyrightconfig.json{ "include": [ "src" ], "reportTypeshedErrors": false, "reportMissingImports": true, "reportMissingTypeStubs": false, "pythonVersion": "3.7", "pythonPlatform": "Linux", "executionEnvironments": [ { "root": "src" } ] }pyrightconfig.jsonの詳しい書き方は他の記事を参照してください。(もしかしたら自分が他に書くかも)
ここで、
src/main.py
を編集してみましょう。src/main.pydef hello(name: str, age: int) -> str: result1: str = "My name is " + name + ".\n" result2: int = "I am " + str(age) + " years old." return result1 + result2 result: int = 10 result = hello(name="Otao", age=23) print(result)pythonのType Hintsでは、このように関数や変数に型アノテーションを付けることができます。
pyrightを導入した状態でsrc/main.py
を開くと、、、
result2はint型なので、str型は代入できないよ!
str型とint型の+
演算子は定義されてないよ!!
resultはint型で定義されてるのに、そこにstr型を代入しようとしているよ!!!
hello関数の定義も貼っておくね!!!
といった風に、型にまつわるエラーを表示してくれます。Type Hintsを使うことは以下の理由からおすすめです。
- 型を定義することによって可読性がめちゃくちゃ上がる
- 予期せぬ型が変数に入ってきて不具合を起こす可能性が下がる
- VSCode上の入力補完機能が効く
ぜひ導入しましょう。
まぁ不思議なことに(?)このスクリプト、実行はできるんですよねw
(Type Hintsはあくまでアノテーションなので、実行時には無視されます。)/workspaces/python-test# python3 src/main.py My name is Otao. I am 23 years old.終わりに
快適なPythonライフを!
(記事は適宜更新します。)
- 著者情報
- Twitter: @0meo
習得したいプログラミング言語、したくない言語, https://tech.nikkeibp.co.jp/atcl/nxt/column/18/00501/111200004/ ↩
プレス発表 基本情報技術者試験における出題を見直し, https://www.ipa.go.jp/about/press/20190124.html ↩
実際にはホストOSによって挙動が違うことがあり、Dockerfileの修正が必要になることもあります。 ↩
関数へのType Hintsは3.5からあったので正確ではありませんが、変数にも型アノテーションを付けれるようになったのは3.6以降なので、3.6以降を使って欲しいです ↩
- 投稿日:2019-12-21T17:40:01+09:00
ラズベリーパイzeroWにDocokerをインストールしてみた
Dockerのインストール方法
コマンド一行でOKです。
*ただメモリ領域の関係かうまくいかないときがありました。curl https://get.docker.com | shSSHからの接続設定の場合(screen)
sshで作業をするとセッションが切れる場合があるので
screenを利用したほうがいいですよ。Dockerのインストールが完了
Client: Docker Engine - Community Version: 19.03.5 API version: 1.40 Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:36:04 2019 OS/Arch: linux/arm Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.5 API version: 1.40 (minimum version 1.12) Go version: go1.12.12 Git commit: 633a0ea Built: Wed Nov 13 07:30:06 2019 OS/Arch: linux/arm Experimental: false containerd: Version: 1.2.10 GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339 runc: Version: 1.0.0-rc8+dev GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657 docker-init: Version: 0.18.0 GitCommit: fec3683 If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker your-user Remember that you will have to log out and back in for this to take effect! WARNING: Adding a user to the "docker" group will grant the ability to run containers which can be used to obtain root privileges on the docker host. Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface for more information.最下部に記載されていますが、userが利用できるようにするには、
sudo usermod -aG docker your-user簡単にdockerのインストールが完了
- 投稿日:2019-12-21T17:22:00+09:00
Docker setting のShared Drivesでエラーが出たときの対処法
概要
DockerのShared DriveでDドライブを指定したら
FireWallのエラーが出たので、その時の対処方法を載せます。環境
OS : Windows10 pro (64bit)
セキュリティソフト: Norton(ノートン)エラーメッセージ
Firewall detectedということでファイアウォールに引っかかってしまった模様。
対処法
まずはNortonのファイアウォール設定を開きます。
手順2 : ネットワークの設定 > デバイスの信頼 > [設定する]
ドキュメントにあった、以下のIPアドレスを信頼するデバイスとして追加します。
IPアドレス : [10.0.75.0][10.0.75.1]分かりやすいように名前は[Docker0][Docker1]にしました。
備考
取り急ぎの対応ですが、とりあえずエラーメッセージは出なくなりました。
今後もFirewall関連の問題が出てきたらここの記事に追加していきたいと思います。
- 投稿日:2019-12-21T17:11:16+09:00
DockerにPostgreSQLを入れる(使い捨て)
コンテナ作成および起動
docker container run -d --rm --name postgrescon -e POSTGRES_USER=postgresusr -e POSTGRES_PASSWORD=postgrespass -p 5432:5432 postgres
オプション 意味 --name コンテナ名 -d バックグラウンド実行 --rm 停止後にコンテナ削除 -p 5432:5432 ホストのポート:コンテナのポート -e POSTGRES_USER スーパユーザー名 -e POSTGRES_PASSWORD スーパユーザーパスワード postgres 使用イメージ コンテナ動作確認
$ docker container exec -it postgrescon bash root@xxxxxx:/# psql --version psql (PostgreSQL) 11.0 (Debian 11.0-1.pgdg90+2)ログイン
root@xxxxxx:/# psql -U postgresusr psql (11.0 (Debian 11.0-1.pgdg90+2)) Type "help" for help. postgres=#ホストからの接続確認
#psqlのためpostgresqlをインストール $ brew install postgresql #自動起動停止 $ brew services stop postgresql #停止確認 $ brew services list #接続できることを確認する $ psql -h localhost -U postgresusr Password for user postgresusr: #以下のように出ればOK psql (12.1) Type "help" for help. postgresusr=#
- 投稿日:2019-12-21T17:01:37+09:00
Dockerコンテナ(mysql)に接続する
Dockerコンテナ(mysql)にアクセスする
起動中のコンテナを確認する
$docker-compose ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 847c99b0929c nginx:latest "nginx -g 'daemon of…" 20 minutes ago Up 20 minutes 0.0.0.0:8080->80/tcp docker_php_nginx_1 5e2039b237df docker_php_php "docker-php-entrypoi…" 20 minutes ago Up 20 minutes 9000/tcp docker_php_php_1 8193d899b38d phpmyadmin/phpmyadmin:latest "/docker-entrypoint.…" 20 minutes ago Up 20 minutes 0.0.0.0:8888->80/tcp docker_php_phpmyadmin_1 f4ff8b6b8ac3 mysql:5.7 "docker-entrypoint.s…" 22 minutes ago Up 20 minutes 33060/tcp, 0.0.0.0:13306->3306/tcp docker_php_db_1ホストPCからコンテナ(mysql)に接続する
CONTAINER IDを指定
$docker exec -it f4ff8b6b8ac3 bashmysqlに接続
root@f4ff8b6b8ac3:/# mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 5 Server version: 5.7.28 MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ 5 rows in set (0.03 sec)
- 投稿日:2019-12-21T00:39:19+09:00
LiveViewでElixirを評価する(2):Dockerを使ってElixirの実行をサンドボックス化する
LiveViewでElixirを評価する(1)の続きです。
前回までのあらすじ
LiveviewでElixirを実行時評価すると楽しい。が、eval_stringは自由に書かれてしまうと厄介ななシロモノなので、できるだけ安全に実行する方法を模索します。
サンドボックス化
なぜ悪いことをしたいのか?悪いことをしてメリットがあるからやる訳ですね。
Elixir環境から抜け出しても何もない環境なら、無駄な労力を割く人はそうそう居ないでしょう。
という訳で、コードの評価はelixir-alpineなDockerコンテナ上で行いましょう。Docker上でElixirを動かす
dockerは予め入れといてください。
# docker run -it elixir:1.9.4-alpine iex iex(1)>動きますね。コマンド一発で環境の整ったVMが手に入るなんて魔法のようですね。
Docker上のElixirと話す
Node.connect()で他のVM上のノードと話せるようです。やってみましょう。別ホストのVMと話す場合はVM毎に名前を付けつつ、Cookieとやらも指定しておく必要があるそうです。
あと、コンテナから見たホストのアドレスはhost.docker.internalで解決できるそうです。ちなみにアドレス指定でアクセスする場合、--sname でなく--nameで起動していないと怒られるっぽいです。docker上# docker run -it elixir:1.9.4-alpine iex --name e1 --cookie eval iex(e1@d523eb311dbb.localdomain)1>ローカル# iex --name server@host.docker.internal --cookie eval iex(server@host.docker.internal)1>docker上iex(e1@d523eb311dbb.localdomain)1> Node.ping(:"server@host.docker.internal") :pongローカルiex(server@host.docker.internal)1> Node.ping(:"e1@d523eb311dbb.localdomain") :pong話せてますね。実はこれ逆にするとうまくいきません。Host -> Dockerでは名前解決できません(ちゃんと名前つけてないので当然ですが)。
ですが、一度目のDocker -> HostにPingを投げた時にNode.connectが張られてるっぽくて一度話した相手のドメイン名は解決できるようになります。という訳で、コンテナが立ち上がったらホストに繋ぎに行くようにしましょう。
以降、Dockerの上のコードをClient、ホスト側をServerとします。サーバのコード
サーバの待ち受け側のコードです。
server.exsdefmodule Server do use GenServer def init(init) do :global.register_name(:server, self()) {:ok, init} end def start_link() do GenServer.start_link(__MODULE__, [], name: __MODULE__) end def handle_call({:ready, client_name}, _from, state) do :global.sync() client_pid = :global.whereis_name(String.to_atom(client_name)) GenServer.cast(client_pid, :hello) {:reply, client_pid, state} end end Server.start_link()サーバは単なるGenServerでcast :readyを待ち、:helloを投げ返します。
init時に自身のPIDをglobalに:serverとして登録しています。Clientのコード
eval.exsdefmodule Client do use GenServer def init({name, server_name}) do :global.register_name(String.to_atom(name), self()) Node.connect(String.to_atom(server_name)) :global.sync() server_pid = :global.whereis_name(:server) GenServer.call(server_pid, {:ready, name}) {:ok, server_pid} end def start_link(name, server_name) do GenServer.start_link(__MODULE__, {name, server_name}, name: __MODULE__) end def handle_cast(:hello, server_pid) do IO.puts("Hello, I'm Docker") {:noreply, server_pid} end end Client.start_link("client", "server@host.docker.internal")GenServerのinit時に自身の名前の登録と:serverのpidの問い合わせをして、:readyを投げます。castで:helloを受け取ると返事します。
ちょっとお行儀が悪いですが、スクリプト的に動かしています。また、initの段階ではまだGenServerの準備が整っていなさそうなので、init内であれこれメッセージを投げるのもよろしくないです。(上記コードをcallにして、serverからcallされてもメッセージが届きません。)
ついでにDockerfileも作っておきましょう。DockerfileFROM elixir:1.9.4-alpine RUN mkdir /home/eval/ WORKDIR /home/eval/ COPY client.exs /home/eval/client.exs CMD elixir --name client@host.docker.internal --cookie eval client.exs実行
まずdockerのイメージを作っておきます。
client# docker build -t client .これでclientというイメージができました。
次にサーバを動かしておきます、新しくターミナルを立てて
server# iex --name server@host.docker.internal --cookie eval ーS server.exsクライアント用のターミナルに戻ってclientを起動すると、通信できているのが分かります。
client# docker run -it client > Hello, I'm Dockerserver> client is readyServerからClientを立ち上げる
通信はできたので、今度はServerからClinetのコンテナを立ち上げてみましょう。
とりあえず荒っぽくいきましょう。さっきclient側で打ち込んでいたコマンドをSystem.cmdで叩きます。立ち上げまで時間が掛かるので、spawnで別プロセスにしてます。(ちゃんとやるなら、プロセスハンドルをちゃんと保持して、エラー処理やタイムアウトを設けて適切に管理しましょう。)server.exsdef init(init) do :global.register_name(:server, self()) spawn(fn -> System.cmd("docker", ["run", "client"]) end) # <-- 追加 {:ok, init} endさて、再実行なのですが、クライアントのIO.putsが見えないですね。
server# iex --name server@host.docker.internal --cookie eval ーS server.exs > client is readyもう少し会話させましょう。
server.exs# Server モジュールに以下追加 def handle_call({:hello, name}, _from, client_pid) do IO.puts("Hello " <> name <> ", I'm server") {:reply, client_pid, client_pid} endeval.exsdef handle_cast(:hello, server_pid) do GenServer.call(server_pid, {:hello, "client"}) # <- 変更 {:noreply, server_pid} end今回は、Server->Clientは投げっぱなし(cast), Client→Serverはブロッキング(call)としています。Serverは止めたくないけど、Client側は待ってもいいよねという指針です。
次回
ElixirからDockerのコンテナ上のElixirを立ち上げて通信できました。
次は、前回作ったLiveEvalの環境に組み入れていきます。(組合せるとあまりうまく動かなくなってしまったため、次回少し遅れるかもしれません。)