- 投稿日:2020-04-04T23:24:08+09:00
nvidia-container-toolkitでKivyを動かした
困ったこと
Dockerで
nvidia/cuda
のイメージを使用して、Kivyを入れたら以下のエラーが出てしまいます。
どうもlibGL関係のエラーっぽいです。
解決策を探していたのですが、nvidiaから提供されているnvidia/cudagl
のイメージを使ったほうが楽そうだったので、
それで解決しました。
似たようなエラーがROSで起こった気もするのでこっちのイメージを使うほうがいいかもしれません。root@:/work/test_kivy# python3 main.py [INFO ] [Logger ] Record log in /root/.kivy/logs/kivy_20-04-04_4.txt [INFO ] [Kivy ] v1.11.1 [INFO ] [Kivy ] Installed at "/usr/local/lib/python3.5/dist-packages/kivy/__init__.py" [INFO ] [Python ] v3.5.2 (default, Oct 8 2019, 13:06:37) [GCC 5.4.0 20160609] [INFO ] [Python ] Interpreter at "/usr/bin/python3" [INFO ] [Factory ] 184 symbols loaded [INFO ] [ImageLoaderFFPy] Using ffpyplayer 4.3.1 [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_ffpyplayer, img_gif (img_pil ignored) [INFO ] [Window ] Provider: sdl2(['window_egl_rpi'] ignored) libGL error: No matching fbConfigs or visuals found libGL error: failed to load driver: swrast [INFO ] [Window ] Provider: x11(['window_egl_rpi', 'window_sdl2'] ignored) libGL error: No matching fbConfigs or visuals found libGL error: failed to load driver: swrastDockerfile
kivyのインストールを含めたDockerfileをメモとして残して起きます。
DockerfileFROM nvidia/cudagl:10.1-devel-ubuntu16.04 ENV NVIDIA_VISIBLE_DEVICES ${NVIDIA_VISIBLE_DEVICES:-all} ENV NVIDIA_DRIVER_CAPABILITIES ${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics # ここは自分の好きなツールを入れています RUN apt-get update && apt-get -y upgrade && apt-get install -y wget unzip tree git vim byobu && \ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN apt-get update && apt-get install -y build-essential zlib1g-dev libssl-dev libffi-dev &&\ apt-get install -y build-essential checkinstall libreadline-gplv2-dev && \ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN apt-get update && apt-get install -y libncursesw5-dev libssl-dev libsqlite3-dev &&\ apt-get install -y tk-dev libgdbm-dev libc6-dev libbz2-dev mesa-utils libgl1-mesa-glx cmake &&\ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN apt-get update && apt-get install -y libsdl2-dev &&\ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* RUN mkdir /workspace RUN cd /workspace && wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz &&\ tar zxvf Python-3.7.3.tgz &&\ cd /workspace/Python-3.7.3 &&\ ./configure --enable-optimizations --enable-shared CFLAGS=-fPIC &&\ make -j8 && make install && ldconfig RUN python3 -m pip install kivy RUN python3 -m pip install kivy_examples RUN python3 -m pip install ffpyplayer WORKDIR /workspace RUN rm Python-3.7.3.tgzbuild & run
$ docker build . -t kivy_test:latest $ xhost + $ docker run -it --gpus all --net host -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix kivy_test:latestあとは、Tutorials(翻訳済み) » Pong Game Tutorial(翻訳済み)に載っているサンプルを動かして動作確認しました。
cupy,chainer(GPU)が動くことはサンプルで確認しました。参考サイト
- 投稿日:2020-04-04T22:38:33+09:00
DockerでReactの開発環境を作る
初投稿です。春から大学生の雑魚です。人生ハードモード。
色々不備があると思いますけど、優しくしてね???(?コワイヨォーーーー)Dockerとは
日本語のドキュメントによると
Docker とは、開発者やシステム管理者が、アプリケーションの開発、移動、実行するためのプラットフォームです。
「チーム内で同じ開発環境で開発する事を助けるアプリケーション」って感じです。
用語
コンテナ
アプリケーションの実行を行う開発環境のこと。イメージの情報を元に構築される。
イメージ
コンテナの元となる。コンテナ内の情報が保存されている。
Dockerfile
イメージの内容を記述するファイル。イメージをの元となる。ビルドを行うと、Dockerfileに記述した情報を元にイメージが作成される。
まとめると
- Dockerfileを記述
- ビルドを実行しイメージを作成
- イメージをもとにコンテナを実行
- コンテナ内でアプリケーションを実行
こんな感じになると思います。
実際に書いてみる
Dockerのインストール
テキトーにやってください!???
Dockerで実行するアプリの構築
初めに、コンテナ内で実行したアプリをローカルで作成します。
terminal$ npx create-react-app docker-practice $ cd docker-react-example $ yarn startDockerfileを書く
コンテナの内容を書いていきます。
terminal$ touch DockerfileDockerfile# ベースイメージの作成 FROM node:12.16.1 # コンテナ内で作業するディレクトリを指定 WORKDIR /usr/src/app # package.jsonとyarn.lockを/usr/src/appにコピー COPY ["package.json", "yarn.lock", "./"] # パッケージをインストール RUN yarn install # ファイルを全部作業用ディレクトリにコピー COPY . . # コンテナを起動する際に実行されるコマンド ENTRYPOINT [ "yarn", "start" ]各種コマンド解説
FROM
Dockerfileには必須のコマンド。
ベースとなるイメージをDocker Hubから取って来る。
今回はnodeの12.16.1を取って来ている。WORKDIR
コンテナ内の作業用ディレクトリを指定する。rootとusr内には色々とデフォルトでファイルがあるから、そこは避けたほうがいいみたい。
COPY
ローカルにあるファイルをコンテナ内にコピーする
構文は
1. COPY <ソース>... <送信先>
2. COPY ["<ソース>",... "<送信先>"]
のどちらかRUN
ビルド時にだけ実行されるコマンド(?)。
初回だけで実行したいコマンドを書くと?ENTRYPOINT
コンテナの起動時に実行される。
似たようなコマンドにCMDというのがあるが、ここで説明すると万里の長城長くなるので割愛なんでpackage.jsonとyarn.lockを先にコピーしてんの?
この記事によると、
dockerはビルド開始時にdocker daemonにDockerfileのディレクトリにあるファイルを全部
tar
して送る。
これが大きいとtarするのに時間がかかるみたいなんで、コンテナ内にパッケージの一覧とバージョンの依存関係が書かれたファイルだけコピーして、その後コンテナ内でインストールした方が早いみたいですね!!!
イメージをビルド
コマンドの構文はこんな感じ
→ docker build [オプション] パスterminal$ docker build -t test:1.0 ./-tは名前とタグを指定できる(tagはバージョンみたいなやつ)
指定しなければ名前:latestになる(多分)また、作成したイメージは
terminal$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test 1.0 335dbb73b720 40 seconds ago 1.22GB node 12.16.1 d834cbcf2402 5 weeks ago 916MBで見ることができる。
コンテナを起動
作成したイメージを元にコンテナを起動するで!
コマンドの構文
→ docker run [オプション] イメージ [コマンド] [引数...]terminal$ docker run -it --name sample -p 3000:3000 -v $PWD:/usr/src/app test:1.0terminalCompiled successfully! You can now view docker-react-example in the browser. Local: http://localhost:3000 On Your Network: http://172.17.0.2:3000 Note that the development build is not optimized. To create a production build, use yarn build.
こんな画面が出て
http://localhost:3000 にアクセスして
こんな画面が出たら成功です。ファイルを編集すると、
src/App.jsimport React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Dockerの勉強やでーwwww </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn Ruby on Rails </a> </header> </div> ); } export default App;各オプション解説
-it
-iと-tっていうオプションを一気に指定している。
-tは疑似ターミナルの割当
-iはアタッチしていなくても STDIN をオープンにし続けているらしい。-p
コンテナのポートとホストのポートの関連付けを行う
ホスト:コンテナの順番で指定するので、今回の場合はホストの3000がコンテナの3000と接続されている。-v
ホストのファイルのパス:コンテナのファイルのパスで指定する
volumeの略。ホスト内のファイルをコンテナ内のディレクトリにマウントして、
ホスト上で行ったファイルの変更をあたかもコンテナ上で行ったかのように見せることができる。
これによってファイルの差分を自動が実現されている。--name
コンテナの名前を指定
今回はsampleと指定している。--rm(おまけ)
--rmをつけるとコンテナを停止した時に自動で削除してくれる。
これでホストがコンテナだらけになることを防ぐことができる。起動中のコンテナに入る
docker execで起動中のコンテナに入ることができる。
構文は
terminaldocker exec [オプション] コンテナ コマンド [引数...]
terminal$ docker exec -it sample bash root@fe248383642c:/usr/src/app# root@fe248383642c:/usr/src/app# ls Dockerfile docker-command.md docker-compose.md dockerfile.md node_modules package.json public src yarn.lock root@fe248383642c:/usr/src/app# # exitで抜けることが出来ます。 root@fe248383642c:/usr/src/app# exit exit $こんな感じでファイルをイジイジすることができます。
起動しているコンテナを一覧で表示
docker ps で出来ます。
-aオプションを付けると停止中のコンテナも出てきます。terminal$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe248383642c test:1.0 "yarn start" 24 hours ago Up 13 minutes $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe248383642c test:1.0 "yarn start" 24 hours ago Up 4 minutes 0.0.0.0:3000->3000/tcp sample bac4be724af7 docker-ruby_ruby "irb" 39 hours ago Exited (1) 18 hours ago ruby c2346fe966a2 test "yarn start example" 2 days ago Exited (1) 24 (中略)コンテナの停止
docker stop コンテナ名 で出来ます。
terminal$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe248383642c test:1.0 "yarn start" 24 hours ago Up 13 minutes 0.0.0.0:3000->3000/tcp sample $ docker stop sample sample $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES $コンテナの再起動
docker restart コンテナ名 で出来ます。
terminal$ docker restart sample sample $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe248383642c test:1.0 "yarn start" 24 hours ago Up 7 seconds 0.0.0.0:3000->3000/tcp sample終わりに
大体よく使うコマンドとかについて触れられたかなと思います。
Dockerの内部構造はあまり理解できてないので、別の記事でアウトプットしたいなーって感じです。
- 投稿日:2020-04-04T22:28:22+09:00
[Docker] webコンテナからdbコンテナへの接続方法
docker-compose.yml:docker-compose.yml version: '3' services: db: container_name: local-mysql image: mysql:5.7 volumes: - ./db/mysql_data:/var/lib/mysql environment: MYSQL_DATABASE: 'local-mysql-db' MYSQL_PASSWORD: password MYSQL_USER: root ports: - "3306:3306" networks: - app-net web: container_name: "local-application" build: . command: rails s -p 3000 -b '0.0.0.0' volumes: - .:/fishingshares ports: - "3000:3000" depends_on: - db links: - db networks: - app-net networks: app-net: driver: bridge$ mysql -h local-mysql -u root -D local-mysql-db -p詳しく解説すると、
mysql -h [host名] -u [ユーザ名] -D [database名] -p
ということになる。以上のコマンドをwebコンテナ内で実行すると、mysqlに接続できる。
以上
- 投稿日:2020-04-04T18:06:34+09:00
docker-composeで起動したプロセスのUID、GIDをホストユーザと同じにする
dockerは本当に便利で、何でもdockerで開発をしています。
でもちょっと不満があるとすれば、コンテナの中のユーザと、ホスト側で実行したユーザのUID/GIDが異なるため、
コンテナ内のユーザがvolumeマウントして生成するファイルが、ホスト側のユーザパーミッションで書き換えられない
というのが不満でした。どう解決するのか
この環境はプロダクション環境で使うのではなく、あくまで開発環境で使用することを想定しています。
nodeのオフィシャルイメージだと最初からnodeユーザが登録されているので、
コンテナ内で何かしら動かす際にnodeユーザで実行することを想定しています。
悩んだ挙げ句、とりあえず落ち着いたのは以下。ホストユーザのUID、GIDを環境変数としてコンテナに渡す
.envファイルを作成し、以下のような情報を記述。
記述する際にはシェルスクリプトを準備して作成。make_env.sh#!/bin/bash set -eu cat <<EOT > .env LOCALUID=`id -u` LOCALGID=`id -g` EOT生成されたファイルは以下な感じ。
.envLOCALUID=1003 LOCALGID=1003entrypointでUID/GID を変更する
nodeのオフィシャルイメージだと最初からnodeユーザが登録されている。
コンテナ内で何かしら動かす際にnodeユーザで実行する。entrypoint.sh#!/bin/bash set -eu # 一時的なグループを作成 groupadd -g 11111 tmpgrp # nodeユーザを一時的なグループに一旦所属させる usermod -g tmpgrp node # もともと所属していたnodeグループを削除 groupdel node # ホストユーザのGIDと同じGIDでnode グループを作成 groupadd -g $LOCALGID node # nodeユーザのGID をホストユーザのGIDに設定 usermod -g $LOCALGID node # nodeユーザのUID をホストユーザのUIDに設定 usermod -g $LOCALUID node # 一時的に作ったグループを削除 groupdel tmpgrp su node exec "$@"結果
以下のようなdocker-compose.yamlを作成して実験。
docker-compose.yamlversion: "3" services: node: image: node:lts-buster-slim volumes: - ./app:/app - ./entrypoint.sh:/entrypoint.sh:ro entrypoint: /entrypoint.sh env_file: - ./.env無事ホストユーザと同じUID/GIDに変更されていることが確認。
$docker-compose run --rm node bash node@e9aa2121a23f:/$ id uid=1003(node) gid=1003(node) groups=1003(node) node@e9aa2121a23f:/$一人で自マシン上で開発しているのならUID/GIDが1000でコンテナ内のUID/GIDも1000で同じだから気にしなくても
良いかなと思うのですが、会社内で共有PC上で開発していると、UID/GIDの1000じゃなくなるのでちょっと困っていました。
これをベースイメージとして社内で使えば、root権限を与えなくてもコンテナが生成したファイルやディレクトリを
ホストユーザが編集・削除できるようになりそうです。
- 投稿日:2020-04-04T13:15:37+09:00
PHPがない環境でEmacsでPSR2のflycheckを使用する
Dockerを使って開発している場合、Emacsエディタが動いている環境にPHPがインストールされていない場合もよくあると思います。
EmacsでPSR2のflycheckを使って文法チェックを動かすためには、phpcsコマンドが使える必要があるので、わざわざPHPからインストールするのかという問題が出てきます。それを避けるために、phpcsのDockerコンテナを使ってEmacsでflycheckを動かす方法を紹介します。
※ Docker等のインストールは完了していることが前提となります。
※ Docker化によるオーバーヘッド等の検証はまだ行っておりません。環境
Ubuntu: 18.04
Docker: 19.03
Emacs: 25.2セットアップ
以下の内容のファイルを作成します。
/usr/local/bin/phpcs#!/bin/bash docker run -i -v $(pwd):$(pwd) -w=$(pwd) --rm phpqa/phpcs $@実行権限を与えます。
chmod 755 /usr/local/bin/phpcs
動作確認します。
phpcs --version
これでEmacsが正しく設定されていればflycheckが正しく動作するようになるはずです。
参考
ここでは細かい.emacs側の設定はスキップしますが、参考までにこのようにflycheckを有効化しています。
.emacs(add-hook 'php-mode-hook '(lambda () (setq flycheck-phpcs-standard "PSR2") 'php-enable-psr2-coding-style )) (add-hook 'after-init-hook #'global-flycheck-mode)
- 投稿日:2020-04-04T11:59:19+09:00
[Microsoft] CLIから始めるSQL Server
これはなに?
docker pullしてrunしたはいいけれど、SQL Server Management Studio (通称SSMS)がないゆえに、CLIからSQL Serverを使うことになった男のメモです。
接続
sqlcmd -H ホスト名 -U ログインID -P パスワード
データベースを指定する場合は
-d データベース名
をつける例)
sqlcmd -H localhost -U sa -P password2020! -d mydb
SQLファイルを読み込み
sqlcmd -H ホスト名 -U ログインID -P パスワード -i ファイル名
ファイルがいくつもある場合は、こんな感じでどうでしょうか。bash/zsh使いのひと用です。
for a in *.sql; do sqlcmd -H ホスト名 -U ログインID -P パスワード -i "$a" done
xargs
のほうがいいかもしれません。ls -1 *.sql | xargs -I% sqlcmd -H ホスト名 -U ログインID -P パスワード -i %ファイル名にバージョン番号がついている(例えば、migration-1.0.0.sqlとか)場合は、
sort --version-sort
で並べ直すと幸せになれます。(おまけ) Dockerから始めるSQL Server
Macのひとは、Docker Desktopをインストールします。
Docker hubを参照して、好みのバージョンのSQL Serverをpullします。
下記は2017を落とす場合です。
docker pull mcr.microsoft.com/mssql/server:2017-latest
コンテナを起動します。
mssqlという名前をつけました。
カレントディレクトリを/mnt
にマウントして、コンテナ内から見えるようにしました。docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=password2020!' -p 1433:1433 --name mssql -v "$PWD:/mnt" -d mcr.microsoft.com/mssql/server:2017-latest
sqlcmd
コマンドはこのように実行します。
作業ディレクトリを/mnt
にしています。docker exec -it -w /mnt mssql /opt/mssql-tools/bin/sqlcmd
(なんでPATH通ってないんや。。。)
(おまけその2) SQLから始めるSQL Serverデータベース
データベースを作ったり、ユーザーを作ったりするSQLは別記事に書きました。
- 投稿日:2020-04-04T03:04:24+09:00
MANスタック(MongoDB, Angular, Nest.js)をdocker-compose一発で起動する
始めに
MANスタックってなに?
JavaScriptでWebアプリを開発する方にとっては、MEANスタック(MongoDB + Express + Angular + Node.js)が馴染み深いのではないでしょうか?
MEANスタックの Node.js + Express を Node.js のフレームワークの Nest.js に置き換えたものがMANスタック(MongoDB + Angular + Nest.js)です!
MANスタック自体の説明等は、Rapid full stack for Angular developers— The MAN Stack (Part I) を参照してください。
MEANスタックに比べてどうなの?
Nest.js は、デフォルトで Expressをwrapしています。MEANスタックで今まで開発していた方であれば、特に苦労することなく乗り換えることができるのではないでしょうか?
また、Angularに非常に影響を受けているフレームワークなので、記法がほとんど一緒です。(特に何もしなくてもTypeScript Onlyな環境で開発できます。)
Angular に影響を受けていると前述しましたが、Spring にもかなり色濃く影響を受けているのではないでしょうか。そういった意味で、Java有識者(Spring有識者)にとっては、開発しやすいフレームワークだと感じています。
本記事終了後にできるようになること
docker-compose up -d
一発でMANスタックのアプリケーションが起動できる。- 本番環境などでそのまま使用することは想定しておらず、あくまで開発時の動作確認を楽にするためと捉えてください。
手順
前提
- Node.js の開発環境整備済み
- Angularの開発環境の整備済み
- Nest.jsの開発環境整備済み
- Docker/Docker Composeの環境整備済み
環境の確認
以下のコマンドを実行できる場合は、前提となる環境構築が済んでいます。
Node.js
$ node --version v12.14.1Angular
$ ng --version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ Angular CLI: 9.0.4 Node: 12.14.1 OS: linux x64 Angular: ... Ivy Workspace: Package Version ------------------------------------------------------ @angular-devkit/architect 0.900.4 @angular-devkit/core 9.0.4 @angular-devkit/schematics 9.0.4 @schematics/angular 9.0.4 @schematics/update 0.900.4 rxjs 6.5.3Nest.js
$ nest --version 6.13.3Docker/Docker Compose
$ docker --version Docker version 17.12.1-ce, build 7390fc6 $ docker-compose --version docker-compose version 1.25.0, build 0a186604Angular, Nest.jsのアプリケーションのひな型作成
Angular
$ ng new angular-sample ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS CREATE angular-sample/README.md (1030 bytes) CREATE angular-sample/.editorconfig (246 bytes) CREATE angular-sample/.gitignore (631 bytes) CREATE angular-sample/angular.json (3631 bytes) CREATE angular-sample/package.json (1291 bytes) CREATE angular-sample/tsconfig.json (543 bytes) CREATE angular-sample/tslint.json (1953 bytes) CREATE angular-sample/browserslist (429 bytes) CREATE angular-sample/karma.conf.js (1026 bytes) CREATE angular-sample/tsconfig.app.json (210 bytes) CREATE angular-sample/tsconfig.spec.json (270 bytes) CREATE angular-sample/src/favicon.ico (948 bytes) CREATE angular-sample/src/index.html (299 bytes) CREATE angular-sample/src/main.ts (372 bytes) CREATE angular-sample/src/polyfills.ts (2835 bytes) CREATE angular-sample/src/styles.css (80 bytes) CREATE angular-sample/src/test.ts (753 bytes) CREATE angular-sample/src/assets/.gitkeep (0 bytes) CREATE angular-sample/src/environments/environment.prod.ts (51 bytes) CREATE angular-sample/src/environments/environment.ts (662 bytes) CREATE angular-sample/src/app/app-routing.module.ts (246 bytes) CREATE angular-sample/src/app/app.module.ts (393 bytes) CREATE angular-sample/src/app/app.component.css (0 bytes) CREATE angular-sample/src/app/app.component.html (25755 bytes) CREATE angular-sample/src/app/app.component.spec.ts (1083 bytes) CREATE angular-sample/src/app/app.component.ts (218 bytes) CREATE angular-sample/e2e/protractor.conf.js (808 bytes) CREATE angular-sample/e2e/tsconfig.json (214 bytes) CREATE angular-sample/e2e/src/app.e2e-spec.ts (647 bytes) CREATE angular-sample/e2e/src/app.po.ts (301 bytes) ✔ Packages installed successfully. Successfully initialized git.Nest.js
$ nest new nest-sample ⚡ We will scaffold your app in a few seconds.. CREATE /nest-sample/README.md (3370 bytes) CREATE /nest-sample/nest-cli.json (64 bytes) CREATE /nest-sample/package.json (1695 bytes) CREATE /nest-sample/tsconfig.build.json (97 bytes) CREATE /nest-sample/tsconfig.json (336 bytes) CREATE /nest-sample/tslint.json (426 bytes) CREATE /nest-sample/src/app.controller.spec.ts (617 bytes) CREATE /nest-sample/src/app.controller.ts (274 bytes) CREATE /nest-sample/src/app.module.ts (249 bytes) CREATE /nest-sample/src/app.service.ts (142 bytes) CREATE /nest-sample/src/main.ts (208 bytes) CREATE /nest-sample/test/app.e2e-spec.ts (630 bytes) CREATE /nest-sample/test/jest-e2e.json (183 bytes) ? Which package manager would you ❤️ to use? npm ✔ Installation in progress... ☕ ? Successfully created project nest-sample ? Get started with the following commands: $ cd nest-sample $ npm run start Thanks for installing Nest ? Please consider donating to our open collective to help us maintain this package. ? Donate: https://opencollective.com/nest動作確認
Angular
$ cd angular-sample $ npm run starthttp://localhost:4200 にアクセスして以下の画面が表示されればOKです。
Nest.js
$ cd nest-sample $ npm run start適当な REST Clientから以下のリクエストを発行し、レスポンスが返却されればOKです。
リクエスト
GET http://localhost:3000 HTTP/1.1レスポンス
HTTP/1.1 200 OK X-Powered-By: Express Content-Type: text/html; charset=utf-8 Content-Length: 12 ETag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE" Date: Sun, 29 Mar 2020 20:15:48 GMT Connection: close Hello World!API作成
一応、一連の連携ができることを確かめるためにNest.jsで簡単なAPIを作成します。作成するAPIの仕様は、以下の様。
/api/book-list
のエンドポイントを持つMongoDBに事前に登録済みの書籍の一覧を取得し、返却する
最低限、動作することを目指すためログ出力やエラー処理などは実装しない
Nest.js は、フレームワーク本体に CLI ツールが存在するので、それを使用してひな型を作成します。
MongoDBを使用するためにライブラリをインストールする
$ npm install --save @nestjs/mongoose mongoose $ npm install --save-dev @types/mongoose接続定義
app.module.tsimport { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; @Module({ // MongoDBコンテナに接続する imports: [MongooseModule.forRoot('mongodb://mongo:27017/sample-app')], }) export class AppModule {}スキーマ作成
book.schema.tsimport * as mongoose from 'mongoose'; export const BookSchema = new mongoose.Schema({ name: String, author: String, detail: String, });Module, Controller, Service のひな型を作成
$ nest generate module book CREATE /src/book/book.module.ts (81 bytes) UPDATE /src/app.module.ts (308 bytes) $ nest generate controller book CREATE /src/book/book.controller.spec.ts (479 bytes) CREATE /src/book/book.controller.ts (97 bytes) UPDATE /src/book/book.module.ts (166 bytes) $ nest generate service book CREATE /src/book/book.service.spec.ts (446 bytes) CREATE /src/book/book.service.ts (88 bytes) UPDATE /src/book/book.module.ts (240 bytes)
nest-sample/src
配下が以下の様であれば、OKです。(必ずしも同じ構成とする必要はないです)src/ |- book | |- book.controller.spec.ts | |- book.controller.ts | |- book.module.ts | |- book.service.ts |- app.controller.spec.ts |- app.controller.ts |- app.module.ts |- app.service.ts |- main.tsbook.module.tsimport { Module } from '@nestjs/common'; import { BookController } from './book.controller'; import { BookService } from './book.service'; import { MongooseModule } from '@nestjs/mongoose'; import { BookSchema } from 'src/schemas/book.schema'; @Module({ imports: [MongooseModule.forFeature([{ name: 'Book', schema: BookSchema }])], controllers: [BookController], providers: [BookService] }) export class BookModule { }book.interface.tsimport { Document } from 'mongoose'; export interface Book extends Document { name: string; author: string; remarks: string; }book.service.tsimport { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { Book } from 'src/interfaces/book.interface'; @Injectable() export class BookService { constructor(@InjectModel('Book') private bookModel: Model<Book>) { } async findAll(): Promise<Book[]> { return this.bookModel.find().exec(); } }book.controller.tsimport { Controller, Get } from '@nestjs/common'; import { BookService } from './book.service'; import { Book } from 'src/interfaces/book.interface'; @Controller('api/book-list') export class BookController { constructor(private readonly bookService: BookService) { } @Get() findAllBook(): Promise<Book[]> { return this.bookService.findAll(); } }ディレクトリ構成
最終的に以下のような構成となりました。(必ずしも同じ構成とする必要はありません。)
src/ |- book | |- book.controller.spec.ts | |- book.controller.ts | |- book.module.ts | |- book.service.ts |- interfaces | |- book.interface.ts |-schemas | |- book.schema.ts |- app.controller.spec.ts |- app.controller.ts |- app.module.ts |- app.service.ts |- main.tsAPIの動作確認をしてみる
動作確認をするために、以下の環境を作成します。
- Nest.js で作成した API サーバを開発モードで起動する
- MongoDB と GUI ツールである Mongo Express を起動する
Nest.js のプロジェクトルートにDockerfileを作成します。
Dockerfile
FROM node:12.14.1 WORKDIR /nest-sample EXPOSE 3000※バージョンはきちんと指定したほうがよいです。安易に
latest
とか使うと痛い目をみる。。.dockerignore
node_modules e2edocker-compose.ymlを書く
sample/ |- angular-sample |- nest-sample |- docker-compose.yml <- ここに配置します。docker-compose.ymlversion: '3.3' volumes: database-data: back-libs: services: # ---------------------------------------- # Backend App # ---------------------------------------- api-server: build: ./nest-sample container_name: api-server working_dir: /nest-sample ports: - '3000:3000' volumes: - ./nest-sample:/nest-sample - back-libs:/nest-sample/node_modules/ tty: true environment: TZ: 'Asia/Tokyo' command: bash -c 'npm install && npm run start:dev' depends_on: - mongo # ---------------------------------------- # Database: MongoDB # ---------------------------------------- mongo: image: mongo container_name: mongo restart: always ports: - '27017:27017' volumes: - database-data:/data/db # ---------------------------------------- # GUI Tool: Mongo Express # ---------------------------------------- mongo-express: image: mongo-express container_name: database-gui-tool restart: always ports: - '8081:8081'アプリケーション(APIとデータベース)を起動する
$ docker-compose up -dAPIをコールする前に、適当なデータを投入しないと何も返却されないのでサンプルデータを格納します。
http://localhost:8081から、データベースとコレクションを作成します。
データベース作成
コレクション作成
サンプルデータ投入
好きなデータを入れてください。
データ例;
{ "_id": ObjectID(), "name": "サンプル1", "author": "サンプル1", "remarks": "サンプル1" }APIをコールしてみる
リクエスト
GET http://localhost:3000/api/book-list HTTP/1.1レスポンス
HTTP/1.1 200 OK X-Powered-By: Express Content-Type: application/json; charset=utf-8 Content-Length: 346 ETag: W/"15a-/jIupJTsvmnPcivYgNhqhupChmU" Date: Mon, 30 Mar 2020 22:10:28 GMT Connection: close [ { "_id": "5e826dd9545e110009be1beb", "name": "サンプル1", "author": "サンプル1", "remarks": "サンプル1" }, { "_id": "5e826de5545e110009be1bed", "name": "サンプル2", "author": "サンプル2", "remarks": "サンプル2" }, { "_id": "5e826df5545e110009be1bef", "name": "サンプル3", "author": "サンプル3", "remarks": "サンプル3" } ]OK!
フロントエンド実装
作成したAPIを実際に使用するクライアントを実装します。
HttpClientを使用するための準備
HttpModuleをルートモジュール(app.module.ts)でインポートします。
app.module.tsimport { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, ], bootstrap: [AppComponent] }) export class AppModule { }HttpClientを使用するコンポーネントを作成する
$ ng generate module book-list $ ng generate component book-list※moduleを追加したら、ルートモジュールにも作成したモジュールを追加してください。
ルーティングの設定を行う
app-routing.module.tsimport { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { BookListComponent } from './book-list/book-list.component'; const routes: Routes = [ { path: '', redirectTo: '/book-list', pathMatch: 'full' }, { path: 'book-list', component: BookListComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }app.component.html<router-outlet></router-outlet>
book.tsexport interface Book { name: string; author: string; remarks: string; }book-list.service.tsimport { Injectable } from '@angular/core'; import { HttpClient, HttpResponse } from '@angular/common/http'; import { Book } from '../book-list/book'; @Injectable({ providedIn: 'root' }) export class BookListService { constructor(private readonly httpClient: HttpClient) { } async findAll(): Promise<HttpResponse<Book[]>> { return await this.httpClient.get<Book[]>('/api/book-list', { observe: 'response' }).toPromise(); } }book-list.component.tsimport { Component, OnInit } from '@angular/core'; import { BookListService } from '../services/book-list.service'; import { Book } from './book'; @Component({ selector: 'app-book-list', templateUrl: './book-list.component.html', styleUrls: ['./book-list.component.css'] }) export class BookListComponent implements OnInit { bookList: Book[] = []; constructor(private readonly bookListService: BookListService) { } ngOnInit(): void { } async search(): Promise<void> { await this.bookListService.findAll().then(response => { response.body.forEach(book => { this.bookList.push(book); }); }); } }book-list.component.html<h1>Book List</h1> <hr /> <div> <button (click)="search()">search</button> </div> <table> <thead> <th>本の名前</th> <th>著者</th> <th>備考</th> </thead> <tbody> <tr *ngFor="let book of bookList"> <td>{{book.name}}</td> <td>{{book.author}}</td> <td>{{book.remarks}}</td> </tr> </tbody> </table>proxy.config.json{ "/api": { "target": "http://api-server:3000" } }
/api/**
にリクエストが来た場合に、バックエンドのコンテナにリダイレクトするような設定を追加します。package.json{ "name": "angular-sample", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve --proxy-config proxy.config.json --host 0.0.0.0", // 追加 "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, ... 省略 }動作確認
バックエンド(Nest.js + MongoDB)を起動した状態でフロントエンドのアプリケーションを起動します。
$ npm run start「search」ボタンを押下して、先ほどMongoDBに投入したデータが表示されればOKです。
docker-compose.ymlにフロントエンドの設定を追加する
Dockerfile
FROM node:12.14.1 RUN npm install -g @angular/cli WORKDIR /angular-sample COPY package.json ./ RUN npm install COPY . . EXPOSE 4200.dockerignore
node_modules e2edocker-compose.ymlversion: '3.3' volumes: database-data: back-libs: front-libs: services: # ---------------------------------------- # Backend App # ---------------------------------------- api-server: build: ./nest-sample container_name: api-server working_dir: /nest-sample ports: - '3000:3000' volumes: - ./nest-sample:/nest-sample - back-libs:/nest-sample/node_modules/ tty: true environment: TZ: 'Asia/Tokyo' command: bash -c 'npm install && npm run start:dev' depends_on: - mongo # ---------------------------------------- # Database: MongoDB # ---------------------------------------- mongo: image: mongo container_name: mongo restart: always ports: - '27017:27017' volumes: - database-data:/data/db # ---------------------------------------- # GUI Tool: Mongo Express # ---------------------------------------- mongo-express: image: mongo-express container_name: database-gui-tool restart: always ports: - '8081:8081' # ---------------------------------------- # Frontend App # ---------------------------------------- front-app: build: ./angular-sample container_name: front-app working_dir: /angular-sample ports: - '4200:4200' volumes: - ./angular-sample:/angular-sample - front-libs:/angular-sample/node_modules/ tty: true environment: TZ: 'Asia/Tokyo' command: bash -c 'npm run start' depends_on: - api-serverhttp://localhost:4200 にアクセスすれば先ほど作成したバックエンドと連携した画面を使用することができます。
終わりに
作成したサンプルは、こちらに格納してあります。
お手軽に開発できて個人的にはすごく気に入っている技術スタックです!(日本語ドキュメントが少ないことだけが残念)参考