20211224のdockerに関する記事は10件です。

nvidia-dockerセットアップ手順

なんの記事? 本年5月にnvidia-dockerセットアップしたときのメモ書きをqiitaに転記した賞味期限ギリギの記事。 環境 OS: Ubuntu20.04 GPU: GeForce GTX 1070 1. cuda-driversインストール https://developer.nvidia.com/cuda-downloadsから Linux x84_64 Ubuntu 20.04 deb(network) を選択する。 「Installation Instructions」の記述の sudo apt-get -y install cudaをsudo apt-get -y install cuda-drivers に置き換えて実行する。 wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600 sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" sudo apt-get update sudo apt-get -y install cuda-drivers 途中、セキュアブートに関する設定を聞かれるので適当にパスワードを設定し、apt-getが終わったら再起動する。 起動中に「Perform MOK management」の画面になるので、「Enroll MOK」を選択する。 「View key0」と「Continue」の選択が出てくるので「Continue」を選択する。 「No」「yes」の選択で「yes」を選択する。 パスワードを聞かれるので、再起動前に設定したパスワードを入力する。 再起動完了したらnvidia-smiを実行して動けばOK。 2021/05/24時点では、この手順で NVIDIA-SMI 465.19.01 Driver Version: 465.19.01 CUDA Version: 11.3 になる。 2. dockerインストール このサイトの手順に沿ってインポートする。 Ubuntuをインストールしたばかりなので、「Uninstall old versions」はスキップ。 「Installation methods」幾つか方法が示されているが、 その中のオススメされている、「Install using the repository」の方法でインストールする。 dockerインストールに必要なツールをインストール sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg dockerリポジトリ登録(x86_64 / amd64用を選択) echo \ "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null dockerインストール sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io dockerテストラン sudo docker run hello-world sudoなしでdockerを実行するための設定。 セキュリティのため、docker管理用のユーザアカウントで実施すること。 sudo groupadd docker #なんかすでにdockerグループがあるみたい sudo usermod -aG docker $USER newgrp docker dockerテストラン docker run hello-world PC起動時に自動的にdockerデーモンを起動するように設定(Ubuntuの場合はデフォルトで有効になってるのでスキップしてよい) systemctl is-enabled docker systemctl is-enabled containerd で両方enabledになっていたらOK。 なっていないなら以下を実行する。 sudo systemctl enable docker.service sudo systemctl enable containerd.service 3. NVIDIA Container Toolkit(nvidia-docker2)インストール リポジトリの追加 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \ && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list nvidia-docker2インストール sudo apt-get update sudo apt-get install -y nvidia-docker2 sudo systemctl restart docker テストラン sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerで実装しているテーブルの内容をターミナルで確認する方法(rails)

備忘録として Dockerを使ってrailsのアプリケーション実装をしている時に、 テーブルの更新内容を確認したくなったので調べた内容を記録しています。 方法 % docker-compose run web rails db 上記のコマンドを入力すると ターミナルに下記内容が表示されます psql (13.5 (Debian 13.5-0+deb11u1), server 14.1 (Debian 14.1-1.pgdg110+1)) WARNING: psql major version 13, server major version 14. Some psql features might not work. Type "help" for help. ○○_development=# #の後に \d テーブル名; と打てばテーブル詳細が表示されます。 ex: \d users; と入力すれば Table "public.users" Column | Type | Collation | Nullable | Default ------------------------+--------------------------------+-----------+----------+----------------------------------- id | bigint | | not null | nextval('users_id_seq'::regclass) first_name | character varying | | not null | ''::character varying last_name | character varying | | not null | ''::character varying first_name_kana | character varying | | not null | ''::character varying last_name_kana | character varying | | not null | ''::character varying email | character varying | | not null | ''::character varying encrypted_password | character varying | | not null | ''::character varying Indexes: "users_pkey" PRIMARY KEY, btree (id) "index_users_on_email" UNIQUE, btree (email) "index_users_on_reset_password_token" UNIQUE, btree (reset_password_token) Referenced by: TABLE "orders" CONSTRAINT "fk_rails_f868b47f6a" FOREIGN KEY (user_id) REFERENCES users(id) みたいな感じで表示されて確認できます。  終了方法 ○○_development=# \q で抜けることができます!! 最後に 調べていた記事には PostgreSQL利用時の操作になる と記載がありました!!Mysqlではできないのかもしれません。 備忘録として書きましたが誰かの為になることがあれば幸いです!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Advent Calendar 2021 クリスマスを迎えて

Advent Calendar 2021 クリスマスイブを迎えて https://qiita.com/kaizen_nagoya/items/14c36d92240fcf686869 書いてから1日。 誘えたか 知り合いで3人、知り合い以外で3人 後出し目標でごめんなさい。とても怖くて、事前には宣言できませんでした。 最低目標は達成しました。ありがとうございます。 予約だけして記載していただいていない方への、再度のお誘いを12/25にお送りする予定です。 書けたか 目標は24 50以上書いていて、目標の倍の項目数は達成した。 記事の内容が予定の30%くらいのものが70%くらいある。 50*.7*.3+50*.3= 25.5 > 24 おお、質*量的には目標達成。 読めたか Advent Calendarの記事をdockerで動かすという企画を3つ。 記事の集計を5つ。 都合、Advent Calendarの8つは全記事を読んだ。 自分が企画した9つと合わせると、27のAdvent Calendarは読破。 広められたか 自分が企画したり、参加したAdvent Calendarのうち、Qiitaの記事はTweetした。 自分が企画したAdvent CalendarはQiita記事以外もTweetした。 Twitterでのいいね、RTの数はまだ集計していない。普段の4倍くらいの流量だと思う。 facebookでは、自分の記事の紹介だけ、3分の1くらいした。年末までには全部紹介予定。 タグ AdventCalendar2021 のタグが、今日、ようやく他のすべての年を抜いt。 ありがとうございます。3分の1は、私のおかげです。 課題がみつかったか。 Qiitaの課題 いくつかみつかった。勘違いしていないか確かめたら具体的に書く予定。 Twitterとの連携の課題 予定投稿のURLは、自動でTwitterに投稿してくれないらしい。 そこで、手作業をした。自分の分だけでなく、他の投稿者の方の分も手投稿。 facebookとの連携の課題 facebookの行事が、カレンダーの企画とうまく連携できなかった。 プログラム組めばいいのかも。 読書メーターとの連携 これも、どこかにスクリプトを書いておけばよかった。 技術的課題 dockerでうまく動かなかった事項は、洗い出して別記事に。 他の方の投稿で、どこで何をすればどうなるが書いてない記事は追いかけきれず。 動いている人の間での情報交換になっているのは残念。 環境の課題 docker以外でインストールするソフトは、1つもこの期間にインストールできなかった。HDDの問題で技術的課題ではない。 参考資料 Qiita Advent Calendar 2021 に登録された記事は Qiita公開 と Zenn公開 のどちらが多かったか?【Swift でスクレイピング】 新人の方によく展開している有益な情報 自己参考資料 Advent Calendar 2021 クリスマスイブを迎えて Advent Calendar 2021 まとめ作業のお土産 Advent Calendar 協賛者を分析 百点満点の三十点を目指しなさい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerfileベストプラクティス - Node.jsアプリケーション編

この記事は ZOZO Advent Calendar 2021 24日目 の記事です。 概要 最近業務でNode.jsを扱うことがありました。そこでNode.jsアプリケーションをDocker化する上でのチェックポイントとDockerfileベストプラクティスのおさらいをまとめました。 実は Next.jsのドキュメント に答えらしきものがあることに後で気づきました。 環境 $ node -v v16.13.1 $ npm -v 8.1.2 $ docker -v Docker version 20.10.8, build 3967b7d サンプルアプリケーションの作成 サンプルアプリケーションは Next.js を使用しました。 Dockerfileとはあまり関係ないですが、ついでなのでNext.jsの起動方法も確認してみます。 まずは Next.js公式チュートリアル を参考に下記のコマンドを実行します。 $ npx create-next-app nextjs-blog-on-docker --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter" 動作確認をします。 $ cd nextjs-blog-on-docker $ npm run dev > dev > next dev ready - started server on 0.0.0.0:3000, url: http://localhost:3000 event - compiled client and server successfully in 2.5s (158 modules) Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry wait - compiling / (client and server)... event - compiled client and server successfully in 895 ms (174 modules) http://localhost:3000 にアクセスしてアプリケーションが起動しているのを確認したら ctrl+cで停止しておきます。 Dockerfileの作成 アプリケーションのルートディレクトリにDockerfileを作成し、必要最低限の内容を書いて保存します。 $ touch Dockerfile FROM node:16 WORKDIR /app COPY . . RUN npm install RUN npm run build EXPOSE 8080 CMD [ "npm", "start" ] imageをbuildしサイズを確認したところ1.19GBあることがわかりました。 $ docker build . -t nextjs-web-app-on-docker ...略 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nextjs-web-app-on-docker latest 9812cd37e688 4 minutes ago 1.19GB dockerを起動し動作確認をします。 $ docker run -p 8080:3000 -d nextjs-web-app-on-docker fe330307542efd19930e26e0c43ad9121b7d99d79614849a78da3143d15ecb8b $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe330307542e nextjs-web-app-on-docker "docker-entrypoint.s…" 21 seconds ago Up 20 seconds 8080/tcp, 0.0.0.0:8080->3000/tcp, :::8080->3000/tcp romantic_hugle $ docker logs fe330307542e > start > next start ready - started server on 0.0.0.0:3000, url: http://localhost:3000 http://localhost:8080 にアクセスし前述と同じWelcomeページが確認できたのでコンテナは停止しておきます。 $ docker stop $(docker container ls -q) Dockerfileのベストプラクティス ここから本題になります。 1. .dockerignore で不要なファイルを除外 プロダクション環境にデプロイする上で不要なファイルを.dockerignoreに記述して除外します。 加えて.env、.aws、.npmrcなど秘匿情報が書かれている可能性があるファイルもあれば除外しておきます。 **/node_modules/ **/.git **/npm-debug.log ちなみに .gitignore を自動生成するツールとして gibo というものがありますが、 .dockerignore を自動生成する dobo というツールもあるようです。 2. マルチステージ・ビルドを使用する アプリケーションのbuild環境と実行環境を分離して、実行環境には最終的な成果物だけを配置することによりimageサイズの縮小を図ります。 # 依存パッケージのインストール FROM node:16 as deps WORKDIR /app # packeg.jsonとpackage-lock.jsonのみコピーする COPY package*.json ./ RUN npm install # Build環境 FROM node:16 as builder WORKDIR /app COPY . . # depsステージでインストールしたパッケージをコピーする COPY --from=deps /app/node_modules ./node_modules RUN npm run build # 実行環境 FROM node:16 WORKDIR /app ENV NODE_ENV production # ファビコンが格納されたディレクトリをコピーする COPY --from=builder /app/public ./public # buildによって.next配下に生成されたhtml、JSON、JSファイルをコピーする COPY --from=builder /app/.next ./.next COPY --from=builder /app/package.json ./package.json EXPOSE 8080 CMD [ "npm", "start" ] 3. CMDにはnpmコマンドを使用しない npmコマンドはシグナルをNode.jsアプリケーションに転送することができないので、KubernetesからGraceful Shutdownが実行できません。よって npm start の代わりに node_modules/.bin/next start を実行します。 (実は node_modules/.bin/next start でも不十分という話し もあります。別の機会に調べようと思います。) 参考: * nodebestpractices/bootstrap-using-node.japanese.md at master · goldbergyoni/nodebestpractices * 2021年1月時点Next.jsのGraceful Shutdown実装状況調査 - tom-256.log - CMD [ "npm", "start" ] + CMD [ "node_modules/.bin/next", "start" ] 4. 実行環境では軽量なベースimageを使用する ベースimageに含まれているライブラリの数が多いほど脆弱性を生む可能性が高いため、プロダクション環境ではなるべく必要最低限で軽量なimageを使用します。 いくつか候補がありましたが、Googleによってメンテンスされている Distroless を使用することにしました。 - FROM node:16 + FROM gcr.io/distroless/nodejs:16 Distrolessはそのままだとshellにログインもできないので少し工夫が必要です。その方法は後述します。 5. 特権ユーザを使用しない セキュリティ面やDocker内で生成されたドキュメントの権限などに不都合があるので、rootユーザーを使う必要がなければ USER を用いてユーザを変更します。 また、Distrolessはadduserといったコマンドが使えないので、はじめから作成されているnonrootというユーザーを利用します。 参考: Distrolessイメージをroot以外のユーザーで実行する - COPY --from=builder /app/.next ./.next + COPY --from=builder --chown=nonroot:nonroot /app/.next ./.next + USER nonroot コンテナにログインしてユーザーを確認してみます。 シェルにログインするには gcr.io/distroless/nodejs:debug imageを使用します。 - FROM gcr.io/distroless/nodejs:16 + FROM gcr.io/distroless/nodejs:debug # image build $ docker build . -t nextjs-web-app-on-docker --no-cache # シェルにログイン $ docker run -p 8080:3000 --entrypoint=sh -ti nextjs-web-app-on-docker # ユーザーを確認 /app $ whoami nonroot nonrootになっているのが確認できました。 6. npm installの代わりにnpm ciを使用する npm ciはnpm installと同様に依存パッケージをダウンロードします。npm installとの違いはpackage-lock.jsonの更新をしないことで、これによって開発時とプロダクション時のコードの差がなくなります。また、node_modulesディレクトリを削除し常にクリーンインストールを行います。さらに --only=production オプションでプロダクション環境では不要なdevDependenciesなパッケージを削除しimageサイズを抑えることができます。 # 依存パッケージのインストール FROM node:16 AS deps WORKDIR /app COPY package*.json ./ # devDependenciesなパッケージを削除 RUN npm ci --only=production # Build環境 FROM node:16 as builder WORKDIR /app COPY . . RUN npm ci RUN npm run build # 実行環境 FROM gcr.io/distroless/nodejs:16 WORKDIR /app ENV NODE_ENV production COPY --from=builder /app/public ./public COPY --from=builder --chown=nonroot:nonroot /app/.next ./.next # 不要なものが取り除かれたnode_modulesをプロダクションにコピーする COPY --from=deps /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json USER nonroot EXPOSE 8080 CMD [ "node_modules/.bin/next", "start" ] 7. ステップの順番を最適化する package.json、package-lock.jsonの更新頻度は少ないため、先にコピーをしておきnpm ci(パッケージのダウンロード)の処理をキャッシュさせます。その後からbuildステップを実行することで全体の実行時間を短くさせます。 # Build環境 FROM node:16 as builder WORKDIR /app - COPY . . + COPY package*.json ./ RUN npm ci + COPY . . RUN npm run build 8. Lintを使用する Lintツールは hadolint を利用しました。試しにFROMを削除して実行すると下記のようなエラーが出ました。このように事前にミスを防ぎます。 $ brew install hadolint $ hadolint Dockerfile Dockerfile:21 DL3022 warning: COPY --from should reference a previously defined FROM alias 9. 脆弱性スキャンを使用する スキャンツールは Dockle を利用しました。 $ brew install goodwithtech/r/dockle $ dockle nextjs-web-app-on-docker:0.0.1 SKIP - DKL-LI-0001: Avoid empty password * failed to detect etc/shadow,etc/master.passwd INFO - CIS-DI-0005: Enable Content trust for Docker * export DOCKER_CONTENT_TRUST=1 before docker pull/build INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image * not found HEALTHCHECK statement Dockleは見つかった脆弱性を5段階で評価してくれます。 結果 最終的なdockerfileは下記です。 # 依存パッケージのインストール FROM node:16 AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --only=production # Build環境 FROM node:16 as builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # 実行環境 FROM gcr.io/distroless/nodejs:debug WORKDIR /app ENV NODE_ENV production COPY --from=builder /app/public ./public COPY --from=builder --chown=nonroot:nonroot /app/.next ./.next COPY --from=deps /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json USER nonroot EXPOSE 8080 CMD [ "node_modules/.bin/next", "start" ] どれくらいimageが軽くなったか確認します。 $ docker build . -t nextjs-web-app-on-docker:0.0.1 --no-cache ...略 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nextjs-web-app-on-docker 0.0.1 8e81f00afeeb 3 minutes ago 321MB 1.19GB → 321MBまで軽量化することができました。 お疲れさまでした。 明日25日の大トリは @t_shimokawa さんの記事です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Hello Bob!! hexpm/elixirで(Rclexの)Docker環境を整備する

この記事は #NervesJP Advent Calender 2021 の24日目2日目です(大幅に超過してスンマセン 1日目の記事は @mnishiguchi さんの「Nerves電子ペーパーでHello world」でした. Elixir/Erlangバージョンの組合せ問題 世俗派関数型言語Elixir(by @kikuyutaセンセ)は,関数型言語の老舗本舗であるErlang VMの上でイゴいています.ElixirもErlangもそれぞれ活発に開発が進んでいてバージョンアップを繰り返しています. そうなるとバージョンの組合せは無限に爆発していってお姉さん困っちゃうわけですが,それでは皆さんのプロジェクトではどの組合せを使うのが良さそうでしょうか?? ホストに環境構築する場合 とりあえずElixirを使いたい!最新版でええんやでっ!という方は,brewなりaptなりでさくっと入れてもらったら良いかと思います. ホストに所定の組合せを構築したい場合は asdf がだんぜんオススメです. 詳しい解説は #NervesJP Advent Calender 2021 19日目の @torifukukaiou さんによるawesome!!な記事を読むと良いです. Dockerで環境構築する場合 速攻で使うにはDocker Hubにある Elixir Official Image を使えば良いでしょう. サクッと最新版を docker run して bash を起動して,いろいろバージョンを調べてみました. root@b1e975b797c2:/# mix local.hex Are you sure you want to install "https://repo.hex.pm/installs/1.13.0/hex-1.0.1.ez"? [Yn] Y * creating root/.mix/archives/hex-1.0.1 root@b1e975b797c2:/# mix hex.info Hex: 1.0.1 Elixir: 1.13.1 OTP: 24.2 Built with: Elixir 1.13.0 and OTP 22.3 root@b1e975b797c2:/# uname -a Linux b1e975b797c2 5.10.76-linuxkit #1 SMP Mon Nov 8 10:21:19 UTC 2021 x86_64 GNU/Linux root@b1e975b797c2:/# cat /etc/issue Debian GNU/Linux 11 \n \l Officialなので安心ではありますが,ここで気になるのが, 任意の組合せは用意できない.Erlangは固定化されてしまう. OSはDebianがデフォ,あと -slim と -alpine はある.でも他は選べないし,OSバージョンも指定できない. というところです. 無限にある組合せをぜんぶサポートするのは無理ですし,対象プロジェクトによっては特定の組合せでイゴかないこともありえます(とはいっても実際にそんなの体験したことは無いですが:D 対象の開発プロジェクトや依存ライブラリがCIテストの対象としている組合せとか推奨している組合せとかを使っておくのが心理的に安心安全というわけです. ちなみに,みんな大好き!Nervesの執筆時点な最新版v1.7.13では, Erlang/OTP 24.1.5 Elixir 1.12.3-otp-24 に乗っかっておきたいところです. そしてNerves v1.7.13でのCIテスト対象になっているのは, を紐解くと,下記の全5バージョンの組合せになっていました. config.yml <snipped...> jobs: build_elixir_1_13_otp_24: docker: - image: hexpm/elixir:1.13.1-erlang-24.1.7-alpine-3.14.2 <snipped...> build_elixir_1_12_otp_24: docker: - image: hexpm/elixir:1.12.3-erlang-24.1.5-alpine-3.14.2 <snipped...> build_elixir_1_11_otp_23: docker: - image: hexpm/elixir:1.11.4-erlang-23.3.4-alpine-3.13.3 <snipped...> build_elixir_1_10_otp_23: docker: - image: hexpm/elixir:1.10.4-erlang-23.3.4-alpine-3.13.3 <snipped...> build_elixir_1_9_otp_22: docker: - image: hexpm/elixir:1.9.4-erlang-22.3.4.18-alpine-3.13.3 <snipped...> workflows: version: 2 build_test: jobs: - build_elixir_1_13_otp_24 - build_elixir_1_12_otp_24 - build_elixir_1_11_otp_23 - build_elixir_1_10_otp_23 - build_elixir_1_9_otp_22 おっ hexpm/elixir ってこれなんぞ??というのが,今回の記事の発端です. (なお本記事のNerves成分は以上でっす! hexpm/elixir!(とは?? みんな大好きHexの開発チームであるBobさんが公開されているものです. hexpm/elixir - Docker Image | Docker Hub じゃなかった,Bobさんってリポジトリ名みたい:D hexpm/bob: The Builder 現時点のDocker Tagsのページは4098までありました. 1ページあたり25タグ表示なので,4097*25+8 = 102,433タグ!! 最新の 1.13.1 で "Filter Tags" しても69ページまであります!(無限に課金してそう,,, ちなみにもちろん Erlang単体のDocker image もご用意されています. どの組合せが使えるの?? どのElixir x Erlangの組合せを docker build しているのか,リポジトリのコードからは定義されていると思わしき箇所は見つけられませんでした. README#Docker-images には, Docker images for Bob's Elixir and Erlang builds are built periodically. Bob checks for new Elixir and Erlang releases every 15 minutes and builds images for any new versions it discovers. 15分ごとにリリースチェックしてるぜ!などと申しております どうもそれぞれのGitHub tags/releasesをほとんどぜんぶビルドしている気がしなくもない,,, 探検隊の情報を求めます. いちお分かったこととして,アーキテクチャは "amd64" と "arm64" の2種類,OSは "alpine" 2種類 "ubuntu" 5種類 "debian" 6種類 の計13種類を回しているようです. lib/bob/job/docker.ex defmodule Bob.Job.DockerChecker do @erlang_tag_regex ~r"^(.+)-(alpine|ubuntu|debian)-(.+)$" @elixir_tag_regex ~r"^(.+)-erlang-(.+)-(alpine|ubuntu|debian)-(.+)$" @archs ["amd64", "arm64"] # TODO: Automate picking the OS versions @builds %{ "alpine" => [ "3.14.3", "3.15.0" ], "ubuntu" => [ "groovy-20210325", "focal-20210325", "bionic-20210325", "xenial-20210114", "trusty-20191217" ], "debian" => [ "bullseye-20210902", "buster-20210902", "stretch-20210902", "bullseye-20210902-slim", "buster-20210902-slim", "stretch-20210902-slim" ] } <snipped...> 要するにどんだけ組合せあるか分かんないんだけど,,, これだけあれば安心ですねっ!! イゴかしてみる 最新版と思わしき 1.13.1-erlang-24.2-ubuntu-focal-20210325 のタグを試してみました. せっかくなので Ubuntu focal (20.04) を指定しています. $ docker run -it --rm hexpm/elixir:1.13.1-erlang-24.2-ubuntu-focal-20210325 /bin/bash root@ef3e34f05207:/# mix local.hex Are you sure you want to install "https://repo.hex.pm/installs/1.13.0/hex-1.0.1.ez"? [Yn] Y * creating root/.mix/archives/hex-1.0.1 root@ef3e34f05207:/# mix hex.info Hex: 1.0.1 Elixir: 1.13.1 OTP: 24.2 Built with: Elixir 1.13.0 and OTP 22.3 root@ef3e34f05207:/# uname -a Linux ef3e34f05207 5.10.76-linuxkit #1 SMP Mon Nov 8 10:21:19 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux root@ef3e34f05207:/# cat /etc/issue Ubuntu 20.04.2 LTS \n \l かなり嬉しいのが docker image のサイズです.公式のイメージと比較してみましょう. $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE elixir 1.13.1 b032b26101ec 33 hours ago 1.3GB hexpm/elixir 1.13.1-erlang-24.1.7-ubuntu-focal-20210325 f6e2d9dafd82 9 days ago 183MB 1.3GB vs 183MB となりました.なんと約1/10です!! もちろんそのぶん自分勝手に使うにはいろいろ入れないといけないですが,ベースのサイズは小さいほうに限りますよねぇ. RclexのDocker環境に使ってみる Rclexとは,Elixirでロボット向けのROS 2/DDS通信ができるすごいやつです(てきとー 詳しいことはそのうち別の記事で紹介できればです〜 $\huge{May\ the\ BEAM\ be\ with\ your\ Robots!!}$ をRclexでやるには,やっぱりElixir/ErlangとROS 2の環境を同時に整えないといけません.どちらもそれなりに大変です. Alchemist視点でRclexの環境をホスト上(正確にはAzure VM上ですが)に構築してお試しする方法は,またもや @torifukukaiou さんが5日目の記事にまとめてくださっています!! ここまでやるのはメンドいですよね〜 あとGitHub Actionsで素敵にCI回したいし. それと,ROS 2はUbuntuに強く依存していて,さらにROS 2のdistribution(version)に対応したUbuntuのバージョンを揃えないといけません.最新LTSのFoxyであればUbuntu focal (20.04)になります. てなことで,この hexpm/elixir をベースとしてRclex向けのDocker環境を仕立ててみました. ### FIXME according to the target version # base image FROM hexpm/elixir:1.12.3-erlang-24.1.5-ubuntu-focal-20210325 # Set Ubuntu Codename ENV UBUNTU_CODENAME focal # Set ROS_DISTRO environment ENV ROS_DISTRO foxy # force error about debconf ENV DEBIAN_FRONTEND noninteractive # update sources list RUN apt-get clean RUN apt-get update # install additonal packages RUN apt-get install -y git sudo build-essential # install AStyle to format C code (NIFs) RUN apt-get install -y astyle ### install ROS START ### https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html # Set locale RUN apt update && apt -y install locales RUN locale-gen en_US en_US.UTF-8 RUN update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 RUN export LANG=en_US.UTF-8 # Setup Sources RUN apt update && apt install -y curl gnupg2 lsb-release RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu ${UBUNTU_CODENAME} main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null # Install ROS 2 packages RUN apt update RUN apt install -y ros-${ROS_DISTRO}-ros-base # Install ROS 2 packages RUN apt install -y python3-colcon-common-extensions # Setup ROS environment in shell RUN echo 'source /opt/ros/${ROS_DISTRO}/setup.sh' >> ~/.bashrc ### install ROS END # cleanup RUN apt-get -qy autoremove # install hex and rebar RUN mix local.hex --force RUN mix local.rebar --force # check version RUN . /opt/ros/${ROS_DISTRO}/setup.sh && env | grep ROS RUN mix hex.info hexpm/elixir のUbuntu向けな特定バージョンを BASE にして,Installing ROS 2 via Debian Packagesを RUN しまくっているだけです(あと詳しくはコメント読んでください 最初の3構文をいろいろ変えたらいろいろバージョン派生できるので,とっても便利になりました! こんな感じでROS 2(Ubuntu) x Elixir x Erlangの組合せを計10種類用意できて,RclexのGitHub Actionsに登録しています1.Elixir x ErlangはNervesのバージョン組に乗っかっています. foxy-ex1.13.1-otp24.1.7 foxy-ex1.12.3-otp24.1.5 [latest] foxy-ex1.11.4-otp23.3.4 dashing-ex1.12.3-otp24.1.5 dashing-ex1.11.4-otp23.3.4 dashing-ex1.10.4-otp23.3.4 dashing-ex1.9.4-otp22.3.4.18 galactic-ex1.13.1-otp24.1.7 galactic-ex1.12.3-otp24.1.5 galactic-ex1.11.4-otp23.3.4 余談:ros official image使えよ?? あんさんROSも Docker Official Image 出してるの知らへんの?いや知ってますとも〜 当初はこれを BASE にしてイメージ作っていたんですが,erlang-solutions_2.0_all.debの挙動がおかしかったりイメージがでかくなったりいろいろありましてね,,, 詳しく気になる方はこのあたり見てください. おわりに ということでこの記事では Bob さんが素敵に働いてくれている hexpm/elixir を紹介しました. なんといってもベースのイメージが小さいし,OSもある程度の選択肢があるし,Nerves勢だけじゃなくElixir/Erlang勢やPhoenix勢にも意外と知られていない優良情報と言っても過言ではないような気がします(なにごと それでは皆さん,よいDocker x Elixirライフを〜 #NervesJP Advent Calender 2021 の3日目は @torifukukaiou さんの「elixir-desktop/desktop のandroidサンプルをイゴかす」です!(でした!! GalacticはRclexでまだ対応できておらず,正確にはGitHub Actionsでまだ使えていません. ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ハイブリッド・マルチクラウド時代のコンテナイメージ・ポータビリティ 〜マルチアーキテクチャーイメージビルド編〜

コンテナのメリットの一つとしてポータビリティ(可搬性)があります。 アプリケーションをコンテナイメージとしてパッケージングすることで、プラットフォームに依存せずに利用できるという特徴は、昨今のコンテナの普及に大きく貢献していると言えます。 しかしこのポータビリティは、プラットフォームのCPUアーキテクチャーが同一の場合にのみ成立するものであり、アーキテクチャーをまたぐことはできません。様々なアーキテクチャーのプラットフォームを組み合わせて管理していくマルチクラウド環境においては、これは避けては通れない課題です。 この課題に対するソリューションとして開発されているのが、Docker BuildxやBuildahといったマルチアーキテクチャー対応のイメージビルドツールになります。 本記事ではこれらのマルチアーキテクチャーイメージのビルド機能を検証しました。 マルチアーキテクチャーイメージとは 単一のイメージの中に複数のアーキテクチャー形式を含めることができるものを指します。 https://matsuand.github.io/docs.docker.jp.onthefly/desktop/multi-arch/ Docker HubやQuay.ioにおける公式イメージの多くはマルチアーキテクチャーに対応しており、Pullする際に自動で実行環境に合わせたアーキテクチャーのイメージが提供されるため、ユーザーはアーキテクチャーを意識せずに利用することができます。 DockerコマンドのプラグインであるDocker Buildxや、コンテナイメージの操作に特化したツールであるBuildahを使うことで、マルチアーキテクチャーイメージをビルドすることができます。 Docker Buildxによるイメージビルド ビルド環境としてIA MacにDocker Desktopを導入して使用します。 Docker BuildxはDocker Desktopに含まれています。 https://www.docker.com/products/docker-desktop マルチアーキテクチャーイメージをビルドする 以下ステップでイメージをビルドします。 ①マルチアーキテクチャーイメージビルド用のビルダーインスタンスを作成する ②そのインスタンスを使用してマルチアーキテクチャーイメージをビルドする またマルチアーキテクチャーイメージのビルドには、マルチアーキテクチャーイメージに対応するレジストリにイメージを保管する必要があります。ここではDocker Hubを使用します。 ### 事前に使用するイメージレジストリにログインしておく ### ビルダーインスタンスを作成・設定する $ docker buildx create --name multibuilder multibuilder ### ビルダーインスタンス確認 $ docker buildx ls NAME/NODE       DRIVER/ENDPOINT             STATUS   PLATFORMS multibuilder    docker-container   multibuilder0 unix:///var/run/docker.sock inactive ... ### 作成したビルダーインスタンスを使用する $ docker buildx use multibuilder ### amd64とs390x(IBM Z)のマルチアーキテクチャーイメージをビルドする $ cat Dockerfile FROM nginx COPY ./index.html /usr/share/nginx/html $ cat ./index.html multiarch image built on mac $ chmod 644 index.html ### ビルド実行&Docker HubにPush $ docker buildx build --platform linux/amd64,linux/s390x -t xxx/nginx-multiarch:mac --push . [+] Building 23.5s (15/15) FINISHED ... ### Mac上での稼動確認 $ docker run --name nginx -d -p 8080:80 docker.io/xxx/nginx-multiarch:mac $ curl http://localhost:8080 multiarch image built on mac ビルドしたイメージをIBM Zで実行 実行環境にはIBM CloudのHyper Protect Virtual Server(Ubuntu 20.04)です。 これにPodmanを導入して実行しています。 ### IBM Z上からイメージをPullする $ podman pull xxx/nginx-multiarch:mac ✔ docker.io/xxx/itlmc-nginx-multiarch:mac ... $ podman images REPOSITORY                             TAG         IMAGE ID      CREATED       SIZE docker.io/xxx/nginx-multiarch  mac         0fe47c2b2120  14 hours ago  137 MB $ podman run --name nginx -d -p 8080:80 nginx-multiarch:mac cca52fc38526e2ea0e7520702849ef5c082e3ef28450abd7e7c5300d5f2ceb9f $ podman ps CONTAINER ID  IMAGE                                      COMMAND               CREATED        STATUS            PORTS                 NAMES cca52fc38526  docker.io/xxx/nginx-multiarch:mac  nginx -g daemon o...  4 seconds ago  Up 4 seconds ago  0.0.0.0:8080->80/tcp  nginx $ curl http://localhost:8080 multiarch image built on mac Buildahによるイメージビルド ビルド環境はIBM CloudのHyper Protect Virtual Server(Ubuntu 20.04)です。 マルチアーキテクチャーイメージをビルドする Buildahの場合、 ①それぞれのアーキテクチャーのイメージをビルドし、 ②それらのイメージのインデックスとなるマニフェストを作成する というステップです。 このマニフェストファイルをマルチアーキテクチャーイメージとして利用します。 イメージレジストリはDocker Hubを使用します。 ### 事前に使用するイメージレジストリにログインしておく $ cat Dockerfile FROM nginx COPY ./index.html /usr/share/nginx/html $ cat index.html multiarch image built on HPVS $ chmod 644 index.html ### s390xイメージをビルドする $ buildah bud --arch s390x -t docker.io/xxx/nginx-s390x:v1 ... Successfully tagged docker.io/xxx/nginx-s390x:v1 1e9bff381553835b9c8583c267e33bfc29c5874c2d878cdb2667da16fde2db2d ### amd64イメージをビルドする $ buildah bud --arch amd64 -t docker.io/xxx/nginx-amd64:v1 ... Successfully tagged docker.io/xxx/nginx-amd64:v1 207da08ff0d56e125ffb4fcac0214dfd15387f7c511757959cb25af965a1a60c $ buildah images REPOSITORY                    TAG      IMAGE ID       CREATED         SIZE docker.io/xxx/nginx-amd64    v1       207da08ff0d5   6 minutes ago   146 MB docker.io/xxx/nginx-s390x    v1       1e9bff381553   9 minutes ago   144 MB docker.io/library/nginx       latest   f6987c8d6ed5   2 days ago      146 MB ### イメージのPush $ podman push docker.io/xxx/nginx-amd64:v1 ... $ podman push docker.io/xxx/nginx-s390x:v1 ... ### それぞれのアーキテクチャーのイメージを参照するマルチアーキテクチャーイメージ(マニフェスト)を作成する $ buildah manifest create nginx-multiarch:hpvs 5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63 $ buildah manifest add --override-arch=amd64 --override-os=linux --os=linux --arch=amd64 nginx-multiarch:hpvs docker.io/xxx/nginx-amd64:v1 5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63: sha256:87f0a1bdc43d86b6531693834026b32c12b7d29096b3eea756d65d7b05ea6c29 $ buildah manifest add --override-arch=s390x --override-os=linux --os=linux --arch=s390x nginx-multiarch:hpvs docker.io/xxx/nginx-s390x:v1 5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63: sha256:4dd94a2bc2f38584148b291f5532faafe889e811668f6c4366bdd88b2adf9a0e ### マルチアーキテクチャーイメージをPush $ buildah manifest push --all nginx-multiarch:hpvs docker://xxx/nginx-multiarch:hpvs ... ### ローカルのイメージを一旦削除 $ buildah rmi 5510878c5973 207da08ff0d5 1e9bff381553 untagged: localhost/nginx-multiarch:hpvs untagged: docker.io/xxx/nginx-amd64:v1 untagged: docker.io/xxx/nginx-s390x:v1 $ buildah images REPOSITORY                TAG      IMAGE ID       CREATED      SIZE docker.io/library/nginx   latest   f6987c8d6ed5   2 days ago   146 MB ### 改めてマルチアーキテクチャーイメージをPull $ buildah pull docker.io/rkyce/nginx-multiarch:hpvs ... Writing manifest to image destination Storing signatures 1e9bff381553835b9c8583c267e33bfc29c5874c2d878cdb2667da16fde2db2d $ buildah images REPOSITORY                        TAG      IMAGE ID       CREATED          SIZE docker.io/xxx/nginx-multiarch   hpvs     1e9bff381553   21 minutes ago   144 MB docker.io/library/nginx           latest   f6987c8d6ed5   2 days ago       146 MB ### s390xのイメージがPullできていることを確認 $ podman inspect docker.io/xxx/nginx-multiarch:hpvs |grep s390x "Architecture": "s390x", ### 正常に稼動することを確認 $ podman run --name nginx -d -p 8080:80 docker.io/xxx/nginx-multiarch:hpvs ef3bce605bc6e0f675f8546bb74298d6ee940077768e032caa2f3bdcaa0d5df3 $ podman ps CONTAINER ID  IMAGE                                 COMMAND               CREATED        STATUS            PORTS                 NAMES ef3bce605bc6  docker.io/xxx/nginx-multiarch:hpvs  nginx -g daemon o...  7 seconds ago  Up 8 seconds ago  0.0.0.0:8080->80/tcp  nginx $ curl http://localhost:8080 multiarch image built on HPVS ビルドしたイメージをMacで実行 実行環境はIA MacのDocker Desktopです。 ### MacからマルチアーキテクチャーイメージをPull $ docker pull xxx/nginx-multiarch:hpvs $ docker images REPOSITORY                                                                                                                                          TAG               IMAGE ID       CREATED          SIZE xxx/nginx-multiarch                                                                                                                               hpvs              207da08ff0d5   45 minutes ago   141MB ### amd64のイメージがPullできていることを確認 $ docker inspect xxx/nginx-multiarch:hpvs |grep Arch "Architecture": "amd64", ### 正常に稼動することを確認 $ docker run --name nginx -d -p 8080:80 xxx/nginx-multiarch:hpvs 2f43abf7796cf4428f8e333d6a07b32b29a2545eecd78417659734a4a2b1a12a $ docker ps CONTAINER ID   IMAGE                        COMMAND                  CREATED         STATUS         PORTS                                   NAMES 2f43abf7796c   xxx/nginx-multiarch:hpvs   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp   nginx $ curl http://localhost:8080 multiarch image built on HPVS まとめ Docker BuildxとBuildahでそれぞれマルチアーキテクチャーイメージのビルドができることを確認しました。 Docker Buildxは単一のリポジトリに複数のアーキテクチャーのイメージを包含できるのに対し、Buildahのマニフェストと実イメージが分かれる構成となっており、利便性に少し差がある印象です。 またDocker BuildxはDocker社の公式ドキュメントはじめ、Web上で参照できる情報が比較的充実していますが、Buildahはまだ情報が少なく、手探りの検証が必要になります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナ上で動作するNode-REDアプリケーションを簡単に構築する方法

こんにちは。株式会社 日立ソリューションズの山本です。 この記事は、日立ソリューションズグループAdvent Calender 2021の記事になります。 1.はじめに この記事ではNode-REDアプリケーションを作成し、Dockerfileで構築する方法を紹介します。 Dockerfileを使用することで、環境を意識せずにNode-REDアプリケーションを構築することができます。 2.全体の構成 2.1 全体の構成と操作の流れ 本記事で構築する構成と操作の流れを説明します。 # 項目  内容 1 REST API作成  Node-REDでREST APIを作成します。 2 Dockerコンテナ起動 作成したREST APIを指定するDockerfileを作成します。DockerfileをビルドしてDockerイメージを作成し、DockerイメージからDockerコンテナを起動し、Node-REDをDockerコンテナ上に構築します。 3 動作確認 Dockerコンテナ上に構築したNode-REDに対してREST APIリクエストを送信し、レスポンスが返ってくることを確認します。 2.2 ソフトウェアとバージョン情報 本記事で使用したソフトウェアとバージョン情報です。 # ソフトウェア バージョン 1 Docker for windows 3.5.2 2 Node.js 16.3.0 3 Node-RED 2.1.3 3.REST API作成 Node-REDで2つの入力値の合計を返す、REST APIを作成します。 3.1 全体のフロー 全体のフローは以下の通りです。 http inノード、functionノード、http responseノードを順に配置し、接続します。 最終的なフローはこちらです。すぐに試したい方は、コピーしてNode-REDで読み込んでください。 flows.json flows.json [ { "id": "3df6f2735f64a7c9", "type": "tab", "label": "フロー 1", "disabled": false, "info": "", "env": [] }, { "id": "0bbdaac489888327", "type": "http in", "z": "3df6f2735f64a7c9", "name": "", "url": "/test", "method": "get", "upload": false, "swaggerDoc": "", "x": 210, "y": 200, "wires": [ [ "66154fd2213df4c5" ] ] }, { "id": "184e9f8cf1d2dc8d", "type": "http response", "z": "3df6f2735f64a7c9", "name": "", "statusCode": "", "headers": {}, "x": 630, "y": 200, "wires": [] }, { "id": "66154fd2213df4c5", "type": "function", "z": "3df6f2735f64a7c9", "name": "", "func": "msg.payload = {sum : parseInt(msg.req.query.a) + parseInt(msg.req.query.b)};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 200, "wires": [ [ "184e9f8cf1d2dc8d" ] ] } ] 3.2 各ノードの設定 配置した各ノードの設定を行い、REST APIを作成します。 http inノード REST APIの受付口をhttp inノードで設定します。 使用するメソッドをGET 、URLは/testを指定します。 functionノード REST API内の処理を定義します。 GETで受け取ったパラメータa、bに格納された数値を足して、msg.payloadに格納し、フロー上で共有します。 以下のコードをfunctionノードのコード欄に入力します。 msg.payload = {sum : parseInt(msg.req.query.a) + parseInt(msg.req.query.b)}; return msg; http responseノード REST APIのレスポンスとしてmsg.payloadに設定したデータを送信します。 特に設定はいりません。 4.Dockerコンテナ起動 作成したREST APIを指定するDockerfileを作成します。 DockerfileをビルドしてDockerイメージを作成し、DockerイメージからDockerコンテナを起動し、Node-REDをDockerコンテナ上に構築します。 4.1 Dockerfile作成 Node-REDを構築し、作成したREST APIをNode-RED上で起動する手順を記載するDockerfileを作成します。 今回は/dataを作業ディレクトリとします。 #利用するDockerイメージの宣言 FROM node:lts-slim #ビルドツールをインストール RUN apt-get update \ && apt-get install -y build-essential #「/data」というディレクトリを作成し、作業ディレクトリとする WORKDIR /data #Node-REDインストール RUN npm install node-red #flows.jsonを「/data」ディレクトリにコピー COPY ./flows.json /data/ #npmでインストールしたモジュールを格納するパスの設定 ENV NODE_PATH=/data/node_modules #Node-RED起動コマンド CMD node ./node_modules/node-red/red.js --userDir . flows.json 4.2 Dockerイメージ作成 作成したDockerfileを使用してNode-RED及び作成したREST APIを含むDockerイメージを作成します。 Node-REDで作成したflows.jsonとDockerfileを構築する環境のカレントディレクトリに格納します。 カレントディレクトリより、以下のコマンドを実行して、Dockerイメージを作成します。 プロキシ環境内で実行する際はbuild-argオプションを記載してください。 Dockerイメージ名は任意の名称を指定してください。 docker build --build-arg http_proxy=http://<your.proxy.url>:<port>/ --build-arg https_proxy=http://<your.proxy.url>:<port>/ . -t <Dockerイメージ名> 以下のコマンドを実行して、Dockerイメージが作成されたことを確認します。 # Dockerイメージの確認 docker images --- 実行結果例 ここから -------------------------------------------------------------------- REPOSITORY TAG IMAGE ID CREATED SIZE <Dockerイメージ名> latest 196c1ccae37b 18 seconds ago 485MB --- 実行結果例 ここまで--------------------------------------------------------------------- 4.3 Dockerコンテナ起動 作成したDockerイメージからDockerコンテナを起動します。 以下のコマンドを実行します。 -pオプションを使用し、Dockerコンテナの内部で使用するNode-REDのポート1880を外部に公開する際に使用するポートを指定します。 今回は外部にはDockerコンテナをポート8080で公開します。 Dockerコンテナ名は任意の名称、Dockerイメージ名は「4.2 Dockerイメージ作成」で作成したDockerイメージ名を指定してください。 docker run -p 8080:1880 --name <Dockerコンテナ名> <Dockerイメージ名> 5.動作確認 Dockerコンテナ上に構築したNode-REDアプリケーションのREST APIに対してリクエストを送信し、レスポンスが返ってくることを確認します。 ブラウザより、以下のURLにアクセスします。 今回は引数にa=2、b=1を設定します a、bの値を受け取ったNode-REDアプリケーションがa、bの合計値を計算し、{"sum":3}をレスポンスとして送信します。 6.おわりに 本記事ではDockerfileを使用してNode-REDアプリケーションを構築する方法を紹介しました。 Dockerfileを使用することで簡単にNode-REDアプリケーションを構築できるため、作成したNode-REDアプリケーションを構築する際に参考にしてみてください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

chartkickのグラフが表示されない

環境 Docker mysql 8.0 rails6.1.4 ruby3.0.2 intel版Mac使用 考えられる原因 view側(html.erb)のコードの記述の問題でうまくデータを抽出できてないかとも思ったが、 <%= pie_chart [['赤', 50], ['青', 50]]%> と公式のお試しコードで記述してもグラフ出ないので、コーディングの部分ではなさそう。 chromeの検証でconsoleを調べた結果、エラーを発見。 application.js:1 Uncaught Error: Cannot find module 'chartkick/chart.js' at webpackMissingModule (application.js:1) at Module../app/javascript/packs/application.js (application.js:1) とりあえず、JSでエラーが起きてるのは間違いないみたい。 エラー文にはchartkickが見つかりません。と書いてある。 解決策 docker-compose exec web rails action:text install を打ったら解決した。 rails action:text install自体はやってたけど、Docker側にインストールしてなかったのが原因だと思われます。 このコマンドを打つと、マイグレーションファイルが作られる=DBに変更を加えることになる。 マイグレーションをいじるコマンド、つまりDBを操作する訳だから、DBをマウントしてるdocker側に必要な変更がされていなかったことになる。 だからエラーの原因になったのかなと解釈してますが、間違いあればご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】Rails6 API + React(TypeScript)のSPA開発環境を構築する

はじめに 自分用のメモとして記録しておきます。 1. ディレクトリ構成の確認と必要ファイルの用意 以下のディレクトリ構成になるようにファイルを用意する。 $ mkdir backend $ mkdir frontend $ touch docker-compose.yml $ touch backend/Gemfile $ touch backend/Gemfile.lock $ touch backend/entrypoint.sh $ touch backend/Dockerfile $ touch frontend/Dockerfile 2. docker-compose.ymlの編集 docker-compose.yml version: "3" services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql - /tmp/dockerdir:/etc/mysql/conf.d/ ports: - 3306:3306 api: build: context: ./backend/ dockerfile: Dockerfile command: /bin/sh -c "rm -f /myapp/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" image: rails:dev volumes: - ./backend:/myapp - ./backend/vendor/bundle:/myapp/vendor/bundle environment: TZ: Asia/Tokyo RAILS_ENV: development ports: - 3001:3000 depends_on: - db volumes: mysql-data: 3. API側の環境構築 3-1. 各ファイルの編集 backend/Dockerfile FROM ruby:3.0 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs ENV APP_PATH /myapp RUN mkdir $APP_PATH WORKDIR $APP_PATH COPY Gemfile $APP_PATH/Gemfile COPY Gemfile.lock $APP_PATH/Gemfile.lock RUN bundle install COPY . $APP_PATH # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 # Start the main process. CMD ["rails", "server", "-b", "0.0.0.0"] backend/Gemfile source 'https://rubygems.org' gem 'rails', '>= 6.1.4.1' backend/Gemfile.lock # 空のまま backend/entrypoint.sh #!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@" 3-2. Railsアプリケーションの作成 $ docker-compose run --no-deps api rails new . --force -d mysql --api オプションについて docker-compose run に対するオプション --no-deps: リンクしたサービス(今回であればdepends_onで指定したdb)を起動しない rails new に対するオプション --force(-f): ファイルが既に存在している場合は上書きする -d(--database): データベースの種類 --api: apiモードでアプリケーションを作成 3-3. build rails newでGemfileが更新されたのでdocker-compose buildを実行する $ docker-compose build 3-4. database.ymlの編集 backend/config/database.yml default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # デフォルトだと空欄になっているので変更 host: db # デフォルトだとlocalhostになっているので変更 development: <<: *default database: myapp_development test: <<: *default database: myapp_test production: <<: *default database: <%= ENV["DATABASE_NAME"] %> username: <%= ENV["DATABASE_USERNAME"] %> password: <%= ENV["DATABASE_PASSWORD"] %> host: <%= ENV["DATABASE_HOST"] %> 3-5. データベースの作成 データベースを作成しないと以下のようにデータベースがないと怒られます。 $ docker-compose run api rails db:create ー API側の環境構築は以上になります。 4. Front側の環境構築 4-1. docker-compose.ymlにfront側の処理を追加 docker-compose.yml version: "3" services: db: ... api: ... # ↓ 追加 front: build: context: ./frontend/ dockerfile: Dockerfile volumes: - ./frontend:/usr/src/app command: sh -c "cd app && yarn && yarn start" ports: - "4000:3000" volumes: mysql-data: 4-2. Dockerfileの編集 frontend/Dockerfile FROM node:14.18-alpine WORKDIR /usr/src/app 4-3. build $ docker-compose build 4-4. アプリケーション作成 アプリケーション名はappとする。 TypeScriptを使いたので最後に--template typescript を追加する。 nodeのバージョンによってはESlint等をインストールする際にエラーが発生する可能性があるので、適宜、nodeイメージのバージョンを変更する。 参考: https://hub.docker.com/_/node npmで管理する場合 $ docker-compose run --rm front sh -c "npx create-react-app app --template typescript" yarnで管理する場合(<= 今回はこちら) $ docker-compose run --rm front sh -c "yarn create react-app app --template typescript" ※ yarnはnodeのイメージ(node:14.18-alpine)にデフォルトで入っているらしいのでインストールは不要。 参考: https://github.com/nodejs/docker-node/blob/b695e030ea98f272d843feb98ee1ab62943071b3/14/alpine3.14/Dockerfile 4-5. ディレクトリ構成の確認 以下のように指定したappディレクトリ配下にnode_modules, public, srcディレクトリ、pacage.json、tsconfig.json, yarn.lockファイル等が作成されていることが確認できます。 5. 各コンテナを立ち上げる $ docker-compose up -d 6. 確認 API側 http://localhost:3001 にアクセス Front側 http://localhost:4000 にアクセス ー 無事に初期画面が表示されました。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでLaravel×Elasticsearch環境を作る

前提条件 環境 ・ローカル 検証端末:MacOS Monterey (12.1) docker:Docker version 20.10.11, build dea9396 docker-compose:v2.2.1 ・Docker環境 PHP:8.0.13 MySQL:8.0.27 Elasticsearch:7.12.0 読むべき人 Elasticsearch導入したことない人。 家で検証してみたい人。 Elasticという響きがかっこいいなーと思ってる人。 コンテナの構成 ・nginx リクエストを最初に受けるサーバー ・php Laravelが動作するコンテナ。 ・mysql メインのデータストレージとして使用するDB。 ・Elasticsearch 全文検索エンジン。Scout経由で使用する想定。 ・node 画面実装にはないと困るので。 Laravelのモジュールをクローンする git clone https://github.com/laravel/laravel.git 今回作成する環境のディレクトリ構成 elasticsearch_test/ ←ディレクトリ名は任意のものに変更 ├── CHANGELOG.md ├── README.md ├── app ├── artisan ├── bootstrap ├── composer.json ├── composer.lock ├── config ├── database ├── docker ←[追加] 設定ファイルを追加 ├── docker-compose.yml ←[追加] 設定ファイルを追加 ├── package.json ├── phpunit.xml ├── public ├── resources ├── routes ├── server.php ├── src ├── storage ├── tests ├── vendor └── webpack.mix.js 任意のプロジェクト名に変更 今回は「elasticsearch_test」とする。 mv laravel elasticsearch_test Dockerの設定ファイルを追加していく nginxの設定ファイル nginxコンテナ。 Laravelのrootディレクトリはpublic配下なので設定しておく。 listenするポートはコンテナの内側なのでwebサーバーのデフォルトの80でおk。 docker/nginx/default.conf server { listen 80; index index.php index.html; root /var/www/elasticsearch_test/public; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } } phpコンテナのDockerfile phpコンテナはimageではなくDockerfileで設定を指定する。 理由はコンテナ起動時にRUNで叩きたいコマンドがあるからだと思うけど、今回はその辺から拝借してきた記述をそのままにしてある。 docker/php/Dockerfile FROM php:8.0-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y zlib1g-dev mariadb-client vim libzip-dev \ && docker-php-ext-install zip pdo_mysql #Composer install RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" RUN php composer-setup.php RUN php -r "unlink('composer-setup.php');" RUN mv composer.phar /usr/local/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www COPY . /var/www/ RUN composer global require "laravel/installer" php.ini docker/php/php.ini [Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese" docker-compose.yml コンテナ達を1セットに扱うためのdocker-compose。 それの設定ファイルを定義しておきます。 version: '3' services: php: container_name: php_container build: ./docker/php volumes: - ./:/var/www/elasticsearch_test nginx: container_name: nginx_container image: nginx ports: - 81:80 volumes: - ./:/var/www/elasticsearch_test - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php db: container_name: mysql_container image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: database MYSQL_PASSWORD: root TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306 es: container_name: elasticsearch_container image: elasticsearch:7.12.0 ports: - "9200:9200" environment: - discovery.type=single-node - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" ulimits: memlock: soft: -1 hard: -1 node: image: node:12.13-alpine tty: true volumes: - ./src:/var/www working_dir: /var/www コンテナ起動 起動! docker-compose up -d コンテナで実行 vendor周りを作成。 composerの意味がわからずvendor配下を他プロジェクトからコピーしてきていた日が僕にもありました。 依存ライブラリはちゃんとcomposerでインストールしよう! composer install envファイルを作成 cp .env.example .env keyを生成 これあんまり意味分かってない。謎の儀式。 php artisan key:generate 疎通確認 phpコンテナ ブラウザでアクセス localhost:81 mysqlコンテナ コンテナにログイン docker exec -it mysql_container /bin/bash Mysqlにログイン mysql -uroot -proot Databaseを作成する create database elasticsearch_test_db; Mysql8系はデフォルトの接続方法が異なるため変更する ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'; .envファイルのDBホスト情報をdocker-composeで定義したサービス名に変更 DB_CONNECTION=mysql DB_HOST=db // ←ここ DB_PORT=3306 DB_DATABASE=elasticsearch_test_db DB_USERNAME=root DB_PASSWORD=root Elasticsearchコンテナ とりあえずコンテナに入る docker exec -it elasticsearch_container /bin/bash Elasticserachコンテナの中からなのでhostは「localhost」 [root@8970f3395096 elasticsearch]# curl -X GET localhost:9200 { "name" : "8970f3395096", "cluster_name" : "docker-cluster", "cluster_uuid" : "JKMTJ9JYRDuTfq0o4phKIQ", "version" : { "number" : "7.12.0", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "78722783c38caa25a70982b5b042074cde5d3b3a", "build_date" : "2021-03-18T06:17:15.410153305Z", "build_snapshot" : false, "lucene_version" : "8.8.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" } .envにElasticsearchの設定を追加。 識別はdocker-compose.ymlのserviceに書いたservice名 SCOUT_DRIVER=elasticsearch ELASTICSEARCH_HOST=es:9200 サンプルとなるDBを用意する migration migrationファイルを作成 php artisan make:migration create_scout_test_records_table --create=scout_test_records database/migrations/2021_12_17_031813_create_scout_test_records_table.php のサンプル <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateScoutTestRecordsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('scout_test_records', function (Blueprint $table) { $table->increments('id'); $table->string('name', 255)->comment('名前'); $table->string('hash_code', 255)->comment('ハッシュコード'); $table->text('text')->nullable()->comment('テキスト'); $table->double('latitude')->nullable()->comment('緯度'); $table->double('longitude')->nullable()->comment('経度'); $table->integer('type')->comment('タイプ'); $table->tinyInteger('status')->comment('ステータス'); $table->timestamps(); $table->softDeletes(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('scout_test_records'); } } Model modelを作成 php artisan make:model ScoutTestRecord Models/ScoutTestRecord.php <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class ScoutTestRecord extends Model { use HasFactory; use SoftDeletes; public $table = 'scout_test_records'; public $dates = ['deleted_at']; public $fillable = [ 'id', 'name', 'hash_code', 'text', 'latitude', 'longitude', 'type', 'status', ]; protected $casts = [ 'id' => 'integer', 'name' => 'string', 'hash_code' => 'string', 'text' => 'string', 'latitude' => 'double', 'longitude' => 'double', 'type' => 'integer', 'status' => 'integer', ]; public static $rules = [ 'name' => 'required|string', 'hash_code' => 'required|string', 'text' => 'string', 'type' => 'integer', 'status' => 'integer', ]; } Seeder seederも作成しておく php artisan make:seeder ScoutTestRecordsTableSeeder <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\ScoutTestRecord; use Faker\Factory as Faker; class ScoutTestRecordsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { ScoutTestRecord::factory()->count(20)->create(); } } DatabaseSeeder.php <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Database\Seeders\ScoutTestRecordsTableSeeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call([ ScoutTestRecordsTableSeeder::class, ]); } } Factory config/app.php factoryの設定をするため一部変更する 'fallback_locale' => 'en', factoryを作成 php artisan make:factory ScoutTestRecordFactory --model=ScoutTestRecord database/factories/ScoutTestRecordFactory.php <?php namespace Database\Factories; use App\Models\ScoutTestRecord; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Carbon; class ScoutTestRecordFactory extends Factory { protected $model = ScoutTestRecord::class; /** * Define the model's default state. * * @return array */ public function definition() { return [ 'name' => $this->faker->name, 'hash_code' => $this->faker->password(), 'text' => $this->faker->realText($maxNbChars = 50, $indexSize = 2), 'latitude' => $this->faker->latitude(-90, 90), 'longitude' => $this->faker->longitude(0, 180), 'type' => $this->faker->randomNumber($nbDigits = 1), 'status' => $this->faker->randomNumber($nbDigits = 1), 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), 'deleted_at' => null, ]; } } DBにデータを登録する php artisan migrate --seed Elasticsearchにデータを連携する 各モジュールの役割は下記の記事で解説してます。 Scoutの設定 まずはScoutをインストールする。 このあとインストールするエンジンがscoutの8.x系に依存しているため、バージョンを指定する。 バージョン指定のセマンティックバージョンの概念はこれがわかりやすかったです。 composer require laravel/scout:^8.0 設定ファイルをバージョン管理配下に配置する php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" 連携したいデータソースのModelにモデルオブザーバを登録する <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Laravel\Scout\Searchable; // 追加 class ScoutTestRecord extends Model { use HasFactory; use SoftDeletes; use Searchable; // 追加 public $table = 'scout_test_records'; ・ ・ ・ エンジンを設定 Elasticsearchのクライアントモジュールをインストール composer require elasticsearch/elasticsearch エンジンは先人達がけっこういっぱい用意してくれてるけど、今回はtamayoさんのやつをチョイス。 composer require tamayo/laravel-scout-elastic エンジンの処理の挙動はカスタマイズしたい場合があるので、app配下にエンジンを継承したファイルを用意する。 mkdir app/Scout/ touch app/Scout/ElasticsearchEngine.php app/Scout/ElasticsearchEngine.php 若干挙動がおかしいところがあったので継承して修正。 <?php namespace App\Scout; use Laravel\Scout\Builder; use Elasticsearch\Client; use Tamayo\LaravelScoutElastic\Engines\ElasticsearchEngine as ScoutElasticsearchEngine; class ElasticsearchEngine extends ScoutElasticsearchEngine { protected $elastic; protected $index; private $query; public function __construct(Client $elastic, $index) { $this->elastic = $elastic; $this->index = $index; } protected function performSearch(Builder $builder, array $options = []) { $params = [ 'index' => $builder->model->searchableAs(), 'type' => get_class($builder->model), 'body' => [ 'query' => [ 'bool' => [ 'must' => [['query_string' => ['query' => "*{$builder->query}*"]]] ] ] ] ]; if ($sort = $this->sort($builder)) { $params['body']['sort'] = $sort; } if (isset($options['from'])) { $params['body']['from'] = $options['from']; } if (isset($options['size'])) { $params['body']['size'] = $options['size']; } if (isset($options['z']) && count($options['numericFilters'])) { $params['body']['query']['bool']['must'] = array_merge( $params['body']['query']['bool']['must'], $options['numericFilters'] ); } if ($builder->callback) { return call_user_func( $builder->callback, $this->elastic, $builder->query, $params ); } return $this->elastic->search($params); } /** * Perform the given search on the engine. * @inheritDoc * @see ScoutElasticsearchEngine::paginate * @param Builder $builder * @param int $perPage (limit) * @param int $page (offset) * @return mixed */ public function paginate(Builder $builder, $perPage, $page) { $result = $this->performSearch($builder, [ 'numericFilters' => $this->filters($builder), 'from' => (($page * $perPage) - $perPage), 'size' => $perPage, ]); $result['nbPages'] = $result['hits']['total']['value'] / $perPage; return $result; } /** * Map the given results to instances of the given model. * * @inheritDoc * @see ScoutElasticsearchEngine::map * @param \Laravel\Scout\Builder $builder * @param mixed $results * @param \Illuminate\Database\Eloquent\Model $model * @return Collection */ public function map(Builder $builder, $results, $model) { if ($results['hits']['total']['value'] === 0) { return $model->newCollection(); } $keys = collect($results['hits']['hits'])->pluck('_id')->values()->all(); $modelIdPositions = array_flip($keys); return $model->getScoutModelsByIds( $builder, $keys )->filter(function ($model) use ($keys) { return in_array($model->getScoutKey(), $keys); })->sortBy(function ($model) use ($modelIdPositions) { return $modelIdPositions[$model->getScoutKey()]; })->values(); } /** * Get the total count from a raw result returned by the engine. * * @inheritDoc * @see ScoutElasticsearchEngine::getTotalCount * @param mixed $results * @return int */ public function getTotalCount($results) { return $results['hits']['total']['value']; } } Providerを読み込む config/app.php 'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, ・ ・ ・ // Elasticsearch Tamayo\LaravelScoutElastic\LaravelScoutElasticProvider::class, // ←これを追加 ], 軽く動作確認 ここまで書いたらphpのコンテナにログインしてScoutが提供しているデータの取り込みスクリプトを実行する。 php artisan scout:import "App\Models\ScoutTestRecord" Imported [App\Models\ScoutTestRecord] models up to ID: 20 All [App\Models\ScoutTestRecord] records have been imported. // こうなれば成功 次はElasticsearchに検索リクエストを投げてみる。 コンテナ間の通信はdocker-composeのおかげでservice名で識別できる。 curl -X GET es:9200/scout_test_records/_search {"took":9,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":20,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"scout_test_records","_type":"App\\Models\\ScoutTestRecord","_id":"1","_score":1.0,"_source":{"id":1,"name":"山田 涼平","has... // 結果が返却されればOK! まとめ MySQL8.0とかPHP8を使ったせいで実プロジェクトで完コピして作業するには難しいかも。 でもおおまかな流れは全て一緒で、変わるとしたらcompsoerを使って依存ライブラリを導入した時のバージョンが変わるくらいかなー。 あと使ったライブラリがあきらか個人名みたいな名前だけどMITライセンス、みたいな感じ、 これってどれくらい信用度あるんだろ。 フレームワーク本体とかよりは信頼度低い気がする。 そのまま使ったら普通にエラーになったし。 クエリの使い方とかちょいちょい上げていきます。 記載漏れとかあったら是非ご連絡ください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む