20220109のdockerに関する記事は12件です。

【Docker】初期データが入ったMySQLコンテナでSQLの練習環境を作る

はじめに Dockerのインストールについては省略します。 初期データはMySQLのWorldを使用しています。 さまざまな国や都市、言語についてのデータで、眺めるだけでも面白いです。 こちらからダウンロード可能です。 ディレクトリ構成は以下の形です。 root ├── mysql │ └── db │ ├── world.sql │ └── my.cnf └── docker-compose.yml docker-compose docker-compose.ymlは以下のように記述します。 docker-compose.yml version: "3" services: mysql: volumes: # これにより./mysql/dbにある.sqlファイルを実行してくれます - ./mysql/db:/docker-entrypoint-initdb.d image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=root container_name: mysql コンテナを立ち上げる コンテナを立ち上げ、作成されたコンテナ内でMySQLに接続します。 $ docker-compose up -d # -dオプションによって、コンテナを立ち上げながらコマンドを入力できます。 $ docker exec -it mysql /bin/bash root@xxxxx:/# mysql -p Enter password: root mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | world | +--------------------+ 5 rows in set (0.01 sec) データベースにworldが確認できれば成功です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker知識の自分なり まとめ①

Dockerという言葉は知っていたけど、何なのか全然わからんなくて先輩に聞いたり自分で調べたりしたことをまとめています。 そもそもDockerって何やねん 別々の箱(コンテナ)に入ったアプリケーションを管理するツール Dockerはコンテナ技術の1つである(Linuxで使用できるからシェアが高いらしい?) 環境構築が楽になり、誰でもコマンド一つで同じ環境が構築できる Dockerファイル,Dockerイメージ,Dockerコンテナ って何やねん 1 2 Dockerファイル Dockerイメージを言語化したもの Dockerイメージ Dockerコンテナの設計図 Dockerコンテナ Docker実際のアプリを入れている箱。このコンテナが起動するとアプリが動く Dockerファイルによって、Dockerイメージが作られる DockerイメージからDockerコンテナが作られる レジストリ,リポジトリ 1 2 レジストリ リポジトリを集めたもの リポジトリ Dockerイメージを集めたもの Dockerイメージの集まりをリポジトリ そのリポジトリの集まりをレジストリ 図で表すと↓↓みたいな感じだと思います まだまだ勉強中です。 追記していきます
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超簡単!Dockerを使ってサクッとAWS ECR + AppRunnerにPython + Flask環境

タイトルは昔の記事をパクりました。以下の記事でプロニチをGCP(Cloud Run)からAWS(App Runner)に移行するにあたりApp Runner周りをまとめてみました。所々、固有名詞でpronichiとなっていますが私のプロジェクト名になるので参考にする方は任意で変更してください。 事前準備 AWS Command Line 導入 DockerイメージとFlask作成 AWS Command Line 導入 既に導入済だと思いますが念の為記載 AWS Command Line をインストール・更新 $ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" $ sudo installer -pkg AWSCLIV2.pkg -target / AWS Command Line 初期設定 予めIAMでユーザー作成しキーを取得してください。 $ aws configure --profile pronichi AWS Access Key ID [None]: AWS Secret Access Key [None]: Default region name [None]: ap-northeast-1 Default output format [None]: json Dockerfileイメージ作成、起動 DockerfileとFlask関連は以下を参照くださいませ。 $ docker build -t pronichi . $ docker run --name pronichi -p 8080:8080 -v ~/Sites/pronichi/:/app -it --rm pronichi Amazon ECR リポジトリ作成、プッシュ ECRリポジトリ作成 $ aws ecr create-repository \ --repository-name pronichi \ --image-scanning-configuration scanOnPush=true \ --region ap-northeast-1 \ --profile pronichi 認証 $ aws ecr get-login-password --region ap-northeast-1 --profile pronichi | docker login --username AWS --password-stdin 758610380088.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded リポジトリにイメージをプッシュ $ docker tag pronichi:latest 758610380088.dkr.ecr.ap-northeast-1.amazonaws.com/pronichi:latest $ docker push 758610380088.dkr.ecr.ap-northeast-1.amazonaws.com/pronichi:latest AppRunner作成・デプロイ 本当はCUIでやりたかったが、GUIで一旦 アップロードしたコンテナイメージ選択、他はデフォルト 確認画面にて「作成とデプロイ」ボタンを押すと初回のデプロイが開始 デプロイ完了はログで確認 デプロイは初回は6分程度、2回目は5分程度かかっていた GCPのCloud Runだともっと早い気がしたが正確に測っていないのでまた計測したいと思う。 デフォルトドメインにアクセスするとページが表示されることを確認 $ curl https://p6drxqx7ku.ap-northeast-1.awsapprunner.com/ TEST 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerで安全にnode.jsウェブアプリをコンテナ化する

Happy New Year! 年末、年始があっという間に終わり、明日は成人の日。 来週からコーディングのオンラインクラスを受けることになった。4−6ヶ月になりそうであるが、無事乗り切れるのか、少々不安も。javascriptを習得するコースなため、最終的にnode.jsのサーバーサイドでのコーディングもできるようになるまでの知識を得られるよう頑張ろう。node.jsの環境構築に不可欠ともいえるdocker。 今回は、10 best practices to containerize Node.js web applications with Docker の翻訳記事のご紹介です。 こんかい翻訳に苦労しmした。読みにくい部分もあると思いますが、どうぞ最後までお付き合いください。 Dockerでnode.jsウェブアプリケーションをコンテナ化するための10のベストプラクティス LiranTal、Yoni Goldberg 2021年1月13日 Webアプリケーション用のNode.js の Dockerイメージの構築方法に関するベストプラクティスについて説明します。 本記事では、本番環境を想定した安全かつ最適化されたNode.js の Dockerイメージを構築するためのガイドラインを提供します。Node.jsアプリケーションを構築する場合において、以下のようなケースで役立つ内容を説明します。 React にサーバーサイドレンダリング(SSR)Node.js 機能を使用してフロントエンドアプリケーションを構築することを考えている Fastify や NestJS、その他のアプリケーションフレームワークを実行させるマイクロサービス用のNode.js の Dockerイメージの正しいビルド方法についてアドバイスがほしい このガイドを書いた理由 Node.jsアプリケーション用のDockerイメージを構築する方法は他のブログなどでも見つけることができます。しかし、多くの記事は単に Node.js の Docker イメージにてアプリケーションを実行することしか説明しておらず、セキュリティやベストプラクティスについての慎重な検討がされていませんでした。 本記事では、Node.js の Web アプリケーションをコンテナ化する方法をステップ・バイ・ステップで学習することができます。まず、シンプルに機能する Dockerfile から始めて、 Dockerfile ディレクティブ における落とし穴や危険性について理解した後、修正をしていきます。 こちらから英語シートシートのダウンロードしてください。 シンプルな Node.js の Dockerイメージの構築 よく見かけるブログ記事の多くは、以下の Node.js の Docker イメージ構築のための基本的な Dockerfile コマンドの開始と終了の説明しかしていません。 FROM node WORKDIR /usr/src/app COPY . /usr/src/app RUN npm install CMD "npm" "start" Dockerfile という名前のファイルにコピーして 、ビルドして実行します。 $ dockerbuild。 -t nodejs-tutorialdocker $run -p 3000:3000 nodejs-tutorial とてもシンプルかつ動作もしますが、Node.js の Docker イメージを構築する際の間違いや悪習慣が含まれていますので、上記方法は絶対に避けてください。 では、 Docker にて最適化された Node.jsWeb アプリケーションを構築できるように、このDockerfileの改善を始めましょう。 このリポジトリをクローンすることで、チュートリアルを進める事ができます。 1. 明示的で決定論的な Docker ベースイメージタグを使用 node Docker イメージをベースにイメージを構築するのは当然のことのように思えるかもしれませんが、イメージを構築するときに実際には何をプルしているのでしょうか?Dockerイメージは常にタグで参照され、タグを指定しない場合はデフォルトである :latest タグが使用されます。 そのため、実際には、Dockerfile に以下のように指定することで、Node.js の Docker ワーキンググループでビルドされた最新版の Docker イメージを常にビルドすることができます。 node からビルド デフォルトの node イメージをベースにビルドする場合の欠点は以下の通りです。 1. Docker イメージのビルドの一貫性が保てない。ちょうど、npmパッケージをインストールするときに、常に決定論的な npm install の動作を行うために lockfiles を使うように、決定論的な docker イメージビルドを得取する方法を取りたいと考えます。イメージをnodeからビルドした場合、これは node:latest タグがあることを意味し、ビルドするたびに node の新たにビルドされた Docker イメージをプルしてしまいます。このような非決定論的な動作が伴う導入は推奨できません。 2. node の Docker イメージは Node.js の Web アプリケーションを実行するために必要なライブラリやツールが満載であるフルサイズのオペレーティングシステムをベースにしています。これには2つのデメリットがあります。まず、イメージが大きくなるということです。ダウンロードサイズも大きくなり、ストレージの必要性が増すだけでなく、イメージのダウンロードと再構築にも時間がかかります。次に、これらのライブラリやツールに存在するかもしれないセキュリティ上の脆弱性をイメージに取り込んでしまう可能性もあります。 実際、 node の Docker イメージは非常に大きく、様々な種類と深刻度が入り混じった数百ものセキュリティの脆弱性を含んでいます。以下の表にもあるように、node を使っている場合、デフォルトで 642個のセキュリティ脆弱性があるイメージが出発点となり、プルやビルドのたびに何百メガバイトものイメージデータがダウンロードされることになります。 より優れた Docker イメージを構築するための推奨事項: 小さな Docker イメージを使用する これにより、Docker イメージのソフトウェアフットプリントが小さくなり、潜在的な脆弱性が減少します。また、サイズが小さくなるため、イメージの構築プロセスが高速化されます。 イメージの静的 SHA256 ハッシュである Docker イメージダイジェストを使用する これにより、ベースイメージから決定論的な Docker イメージビルドを確実に取得できます。 この方針に基づいて、長期サポート (LTS) バージョンの Node.js を使用し、イメージ上のサイズとソフトウェアのフットプリントが最小になるように、最小限の alpine イメージタイプを使用するようにしましょう。 FROM node:lts-alpine これでもまだ、このベースイメージディレクティブは、そのタグの新しいビルドをプルします。その SHA256 ハッシュは、このNode.jsタグの Docker Hubで見つけることができます。また、このイメージをローカルに取り込んだ後、次のコマンドを実行して、出力に Digest フィールドを配置します。 $ docker pull node:lts-alpine lts-alpine: Pulling from library/node 0a6724ff3fcd: Already exists 9383f33fa9f3: Already exists b6ae88d676fe: Already exists 565e01e00588: Already exists Digest: sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a Status: Downloaded newer image for node:lts-alpine docker.io/library/node:lts-alpine SHA256 ハッシュを見つけるための別の方法として、 次のコマンドを実行します。 $ docker images --digests REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE node lts-alpine sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a 51d926a5599d 2 weeks ago 116MB これで、このNode.js の Docker イメージの Dockerfile を次のように更新できます。 FROM node@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a WORKDIR /usr/src/app COPY . /usr/src/app RUN npm install CMD "npm" "start" しかし、上記の Dockerfile では、イメージタグを使わずに Node.js の Docker イメージの名前だけを指定しているため、実際どのイメージタグが使われているのかが曖昧になっています。これでは可読性に欠けるため、メンテナンスが難しく、デベロッパにとって良いユーザーエクスペリエンスとはいえません。 この問題を解決するために、Dockerfile を更新し、 SHA256 ハッシュに対応する Node.js のバージョンの完全なベースイメージタグを提供しましょう。 FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a WORKDIR /usr/src/app COPY . /usr/src/app RUN npm install CMD "npm" "start" 2. Node.js の Docker イメージに本番用で必要な依存関係のみをインストールする 以下 Dockerfileディレクティブは、アプリケーションの機能的な動作には必要のない devDependencies を含むすべての依存関係をコンテナにインストールします。この方法では、開発の依存関係として使用されるパッケージに不要なセキュリティリスクが追加されるだけでなく、イメージサイズも不必要に肥大化してしまいます。 RUN npm install 以前紹介したnpmのセキュリティ10のベストプラクティスから、決定論的なnpm ci ビルドの必要性をご理解していただけたと思います。lockfile から逸脱すると停止するため、継続的インテグレーション(CI)フローでの予期しない挙動を防ぐことができます。 本番用のDockerイメージを構築する場合は、本番用の依存関係のみを確実にインストールしたいので、コンテナイメージに npm の依存関係をインストールする際のベストプラクティスとして以下を推奨します。 RUN npm ci --only=production この段階で更新された Dockerfile の内容は以下の通りです。 FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a WORKDIR /usr/src/app COPY . /usr/src/app RUN npm ci --only=production CMD "npm" "start" 3. Node.jsのツールを本番用に最適化する Node.js の Docker イメージを本番用に構築する際、すべてのフレームワークとライブラリが、パフォーマンスとセキュリティのために最適な設定になっているか確認する必要があります。 そのため、以下のDockerfile ディレクティブを追加する必要があります。 ENV NODE_ENV production npm install の段階で既に本番用の依存関係のみを指定しているので、一見すると冗長に見えますが、なぜ必要なのでしょうか? デベロッパは、NODE_ENV=production 環境変数の設定を、本番環境に関連する依存関係のインストールと関連付けることが多いのですが、この設定には他の影響もあるため、注意が必要です。 フレームワークやライブラリの中には、 NODE_ENV 環境変数が production に設定されていると、本番環境に適した最適な構成でしか動作しないものがあります。これがフレームワークにとって良いことなのか悪いことなのかという意見はさておき、このことを知っておくことは重要です。 例えば、 Express documentation では、パフォーマンスやセキュリティ関連の最適化を有効にするために、この環境変数を設定することの重要性が説明されています。 NODE_ENV 変数はパフォーマンスに大きく影響します。 Dynatrace のデベロッパたちが、ExpressアプリケーションでNODE_ENVを省略した場合の劇的な影響についての詳細をブログ記事で説明しています。 依存している他のライブラリの多くもこの変数が設定されていることを想定している可能性もあるため、Dockerfile にこの変数を設定する必要があります。 アップデートした Dockerfile は、NODE_ENV 環境変数の設定が組み込まれた以下のような内容になります。 FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a ENV NODE_ENV production WORKDIR /usr/src/app COPY . /usr/src/app RUN npm ci --only=production CMD "npm" "start" 4. コンテナを root で実行しない 最小権限の原則は、Unix の黎明期から長く続いているセキュリティ管理であり、コンテナ化された Node.js の Web アプリケーションを実行する際には、常にこれに従うべきです。 脅威の評価は非常にわかりやすいものです。攻撃者が、コマンドインジェクションやディレクトリパストラバーサルを可能にする方法で web アプリケーションを侵害することができた場合、これらはアプリケーション・プロセスを所有するユーザで起動されます。そのプロセスがたまたま root であった場合、攻撃者はコンテナ内で事実上すべてのことを行うことができ、コンテナのエスケープや権限昇格を試みることも可能となります。わざわざ、そのようなリスクを冒す必要はありません。 非常に重要:「コンテナを root として実行させないこと!」 公式の node Dockerイメージや、alpine のようなバリアントには、同じ名前の最小権限ユーザーである node が含まれています。しかし、 node としてプロセスを実行するだけでは十分ではありません。例えば、次のような場合、アプリケーションがうまく機能するためには理想的ではないかもしれません。 USER node CMD "npm" "start" 理由は、USER Dockerfile ディレクティブは、プロセスの所有者が node ユーザーであることを保証するだけだからです。それ以前に COPY 命令でコピーしたすべてのファイルについて考えてみましょう。それらは root が所有しています。これが Docker のデフォルトの動作です。 権限の完全かつ適切な削除方法は以下の通りで、この時点までの最新のDockerfileプラクティスについても示しています。 `FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a ENV NODE_ENV production WORKDIR /usr/src/app COPY --chown=node:node . /usr/src/app RUN npm ci --only=production USER node CMD "npm" "start"@ 5. イベントを適切に処理してNode.jsのDocker Webアプリケーションを安全に終了させる Node.js アプリケーションを Docker コンテナで実行する際のコンテナ化に関するブログや記事でよく見かける間違いの1つは、プロセスの呼び出し方法です。以下や類似する方法は、全て避けるべき悪いパターンです。 CMD “npm” “start” CMD [“yarn”, “start”] CMD “node” “server.js” CMD “start-app.sh” それでは、それぞれの違いと、なぜ全て避けるべきパターンなのかを説明します。 Node.jsのDockerアプリケーションを適切に実行・終了させるための背景を理解るためには、以下の点が重要になります。 1.Docker Swarm や Kubernetes、あるいは Docker エンジン自体などのオーケストレーションエンジンには、コンテナ内のプロセスにシグナルを送る方法が必要です。ほとんどの場合、これらは SIGTERM や SIGKILL のような、アプリケーションを終了させるためのシグナルです。 2.プロセスは間接的に実行される可能性があり、その場合、これらのシグナルを受け取ることは必ずしも保証されません。 3.Linuxカーネルでは、プロセスID1(PID)として実行されるプロセスは、他のプロセスIDとは異なる扱いになります。 この知識を念頭におき、私たちがビルドしている Dockerfile の例から、コンテナのプロセスを呼び出す方法について詳しくみていきましょう。 CMD "npm" "start" ここでの注意点は2つあります。まず、npm クライアントを直接起動することで、間接的にnodeアプリケーションを実行していることです。npm CLI がすべてのイベントを node ランタイムに転送するとは限りません。それを簡単にテストすることができます。 Node.js アプリケーションで、イベントを送信するたびにコンソールにログを記録するSIGHUP シグナル用のイベントハンドラを設定していることを確認してください。簡単なコード例は以下のようになります。 function handle(signal) { console.log(*^!@4=> Received event: ${signal}) } process.on('SIGHUP', handle) 次に、コンテナを実行し、起動したら、 docker CLIと特別な --signal コマンドラインフラグを使用して、SIGHUP シグナルを送信します。 $ docker kill -signal=SIGHUP elastic_archimedes 何も起こりませんでした。これは、npmクライアントが、自分が生成したnodeプロセスにシグナルを転送していないからです。 もう1つの注意点は、Dockerfileに CMD ディレクティブを指定する方法が異なることです。2つの方法があり、それらは同じではありません。 1.シェルフォーム表記では、コンテナがプロセスをラップするシェルインタープリタを起動します。この場合、シェルはシグナルをプロセスに適切に転送しない可能性があります。 execform 表記:シェルをラップせずに直接プロセスを起動します。次のようなJSON 配列表記で指定します。 2.コンテナに送られたシグナルは、そのままプロセスに送られます。例: `CMD ["npm", "start"] その知識に基づいて、Dockerfile のプロセス実行指令を次のように改善します。 CMD ["node", "server.js"] これで node プロセスを直接起動することになり、シェルインタプリタにラップされることなく、送られてきたすべてのシグナルを確実に受け取ることができます。 しかし、これには別の落とし穴があります。 プロセスが PID 1として実行されると、事実上、OSやプロセスの初期化を担当するinit システムの責任の一部を負うことになります。カーネルは、PID 1を他のプロセス識別子とは異なる方法で扱います。カーネルがこのように特別な扱いをするということは、実行中のプロセスに対する SIGTERM シグナルの処理では、プロセスがまだハンドラーを設定していない場合、プロセスを停止するというデフォルトのフォールバック動作が呼び出されないことを意味します。 Node.jsのDockerワーキンググループの勧告を引用がこちらです。「Node.jsはPID 1で動作するように設計されていないため、Docker 内で動作する際に予期せぬ動作を引き起こします。例えば、PID 1として実行されているNode.js プロセスは、SIGINT (CTRL-C) や同様のシグナルに反応しません。」 このため、init プロセスのような動作をする、PID 1で呼び出され、Node.js アプリケーションを別のプロセスとして起動し、すべてのシグナルが Node.js プロセスにプロキシされるようにするツールを使用します。可能であれば、コンテナイメージにセキュリティの脆弱性が追加されないように、ツールのフットプリントをできるだけ小さくする必要があります。 Snyk では、スタティックリンクでフットプリントが小さい dumb-init を使っています。ここでは、その設定方法を紹介します。 RUN apk add dumb-init CMD ["dumb-init", "node", "server.js"] これで、以下のような最新の Dockerfile ができあがりました。イメージ宣言の直後にdumb-init パッケージのインストールを配置しています。これにより、Docker のレイヤーのキャッシュを利用することができます。 FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a RUN apk add dumb-init ENV NODE_ENV production WORKDIR /usr/src/app COPY --chown=node:node . . RUN npm ci --only=production USER node CMD ["dumb-init", "node", "server.js"] 注意:docker kill や docker stop コマンドは、PID 1のコンテナプロセスにしかシグナルを送らないということです。シェルスクリプトで Node.js アプリケーションを実行している場合、例えば /bin/sh のようなシェルインスタンスは子プロセスにシグナルを転送しないので、アプリケーションが SIGTERM を受け取ることはありません。 6. Node.js ウェブアプリケーションの適切なシャットダウン アプリケーションを終了させるプロセス・シグナルについてはすでに説明しましたが、ユーザーに迷惑をかけずに適切にシャットダウンしていることを確認しましょう。 Node.js アプリケーションが、SIGINT、CTRL+Cのような割り込み信号を受信すると、別の動作で処理するようにイベントハンドラが設定されていない限り、突然の kill プロセスが行われます。これは、ウェブアプリケーションに接続されているクライアントが直ちに切断されることを意味します。ここで、Kubernetes によってオーケストレーションされた何百もの Node.js の Web コンテナが、スケールアップやエラー管理のために必要に応じてアップダウンする様子を想像してみてください。決して良いユーザーエクスペリエンスとは言えません。 この問題を簡単にシミュレーションすることができます。ここでは、Fastify Web アプリケーションの例として、エンドポイントの応答が 60 秒遅れることを想定しています。 fastify.get('/delayed', async (request, reply) => { const SECONDS_DELAY = 60000 await new Promise(resolve => { setTimeout(() => resolve(), SECONDS_DELAY) }) return { hello: 'delayed world' } }) const start = async () => { try { await fastify.listen(PORT, HOST) console.log(*^!@4=> Process id: ${process.pid}) } catch (err) { fastify.log.error(err) process.exit(1) } } start() このアプリケーションを実行して、このエンドポイントにシンプルな HTTP リクエストを送信します。 $ time curl https://localhost:3000/delayed 実行中のNode.js のコンソールウィンドウで CTRL+C を押すと、curl リクエストが突然終了したことがわかります。これは、コンテナがダウンしたときにユーザーが受けるのと同じ体験をシミュレートしたものです。 より良い体験を提供するために、次のようにすることができます。 1.SIGINT や SIGTERM のような様々な終了シグナルのイベントハンドラを設定する。 2.ハンドラは、データベース接続や進行中の HTTP リクエストなどのクリーンアップ操作を待ちます。 3.ハンドラはその後、Node.js プロセスを終了させます。 特に Fastify では、ハンドラが fastify.close() を呼び出し、待ち受けるプロミスを返すようにできます。また、Fastify はアプリケーションが利用できないことを示すために、すべての新しい接続に対して HTTP ステータスコード 503 で応答します。 それでは、ここでイベントハンドラを追加します。 async function closeGracefully(signal) { console.log(*^!@4=> Received signal to terminate: ${signal}) await fastify.close() // await db.close() if we have a db connection in this app // await other things we should cleanup nicely process.exit() } process.on('SIGINT', closeGracefully) process.on('SIGTERM', closeGracefully) 上記は Dockerfile に関連するというよりも、一般的な Web アプリケーションに関する問題ですが、オーケストレーション環境ではさらに重要になります。 7. Node.jsのDockerイメージのセキュリティ脆弱性を見つけて修正する Node.js アプリケーションのための小さな Docker ベースイメージの重要性について説明しました。このテストを実践してみましょう。 Snyk CLI を使ってDockerイメージをテストしてみようと思います。Snykの無料アカウントは こちらからサインアップできます。 $ npm install -g snyk $ snyk auth $ snyk container testnode@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a --file=Dockerfile 最初のコマンドでSnyk CLIをインストールし、続いてAPI キーを取得するためにコマンドラインから簡単なサインインフローを行い、セキュリティ上の問題がないかコンテナをテストします。以下はその結果です。 Organization: snyk-demo-567 Package manager: apk Target file: Dockerfile Project name: docker-image|node Docker image: node@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a Platform: linux/amd64 Base image: node@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a ✓ Tested 16 dependencies for known issues, no vulnerable paths found. Snyk は、当社の Node.js ランタイム実行ファイルを含む 16 のオペレーティングシステムの依存関係を検出し、脆弱性のあるバージョンは見つかりませんでした。 では、以下のような FROM node ベースイメージディレクティブを使っていたらどうなっていたでしょうか? FROM node:14.2.0-slim Node.js のバージョンを明確にし、 slim タイプのイメージを使用しているので、Docker イメージ内の依存関係のフットプリントが小さくなっています。では、Snyk でテストしてみましょう。 … ✗ High severity vulnerability found in node Description: Memory Corruption Info: https://snyk.io/vuln/SNYK-UPSTREAM-NODE-570870 Introduced through: node@14.2.0 From: node@14.2.0 Introduced by your base image (node:14.2.0-slim) Fixed in: 14.4.0 ✗ High severity vulnerability found in node Description: Denial of Service (DoS) Info: https://snyk.io/vuln/SNYK-UPSTREAM-NODE-674659 Introduced through: node@14.2.0 From: node@14.2.0 Introduced by your base image (node:14.2.0-slim) Fixed in: 14.11.0 Organization: snyk-demo-567 Package manager: deb Target file: Dockerfile Project name: docker-image|node Docker image: node:14.2.0-slim Platform: linux/amd64 Base image: node:14.2.0-slim Tested 78 dependencies for known issues, found 82 issues. Base Image Vulnerabilities Severity node:14.2.0-slim 82 23 high, 11 medium, 48 low Recommendations for base image upgrade: Minor upgrades Base Image Vulnerabilities Severity node:14.15.1-slim 71 17 high, 7 medium, 47 low Major upgrades Base Image Vulnerabilities Severity node:15.4.0-slim 71 17 high, 7 medium, 47 low Alternative image types Base Image Vulnerabilities Severity node:14.15.1-buster-slim 55 12 high, 4 medium, 39 low node:14.15.3-stretch-slim 71 17 high, 7 medium, 47 low FROM node:14.2.0-slim などの特定の Node.js ランタイムバージョンであれば、安全であるように見えますが、Snyk は2つの主要なソースからセキュリティの脆弱性を見つけました。 1.Node.js ランタイム自体の脆弱性 — Snyk のレポートには 2つの主要なセキュリティの脆弱性が表示されています。これらは、Node.js ランタイムについての既知のセキュリティの問題で、Node.js バージョンをアップグレードすることで即時に修正可能です。Snyk はレポートで修正されたバージョン (14.11.0) についても通知しています。 2.glibc、bzip2、gcc、perl、bash、tar、libcrypt など、この debian ベースイメージにインストールされているツールやライブラリなどです。コンテナ内のこれらの脆弱なバージョンはすぐには脅威にならないかもしれませんが、使わないのに持っている理由を考える必要があります。 この Snyk CLI レポートの一番いいところは、他のベースイメージに切り替えることも Snyk が推奨してくれるところです。代替のイメージを探すのは非常に時間がかかる可能性がありますが、Snyk はその手間を省いてくれます。 ここでの私の推奨は以下の通りです。 1.Docker Hub や Artifactory などのレジストリで Docker イメージを管理している場合は、それらを Snyk にインポートして、プラットフォームがこれらの脆弱性を検出できるようにします。これにより、新たに発見されたセキュリティ脆弱性について継続的に Docker イメージを監視するだけでなく、Snyk の UI で推奨アドバイスを提供することもできます。 2.CI の自動化に Snyk CLI を使いましょう。非常に柔軟性の高い Snyk CLI は、任意のカスタムワークフローに適用することができます。お好みに応じて Snyk for GitHub Actionsも用意しています。 8. マルチステージ・ビルドの使用 マルチステージビルドは、シンプルでありながらエラーが発生する可能性のある Dockerfile から、Docker イメージを構築するステップを分離して、機密情報の漏洩を防ぐことができる優れた方法です。それだけでなく、より大きな Docker ベースイメージを使って依存関係をインストールし、必要であればネイティブの npm パッケージをコンパイルし、alpine の例のように、全てのアーティファクトを小さな本番ベースのイメージにコピーすることができます。 機密情報漏洩の防止 ここで紹介する機密情報の漏洩回避のユースケースは、思ったよりも一般的です。 もしあなたが仕事でDockerイメージを構築しているなら、プライベートな npm パッケージも管理している可能性が高いでしょう。もしそうであれば、おそらくその秘密のNPM_TOKENを npm のインストール時に利用できるようにするための何らかの方法を見つける必要があるでしょう。 こちらがその例です。 `FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a RUN apk add dumb-init ENV NODE_ENV production ENV NPM_TOKEN 1234 WORKDIR /usr/src/app COPY --chown=node:node . . RUN npm ci --only=production RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && \ npm ci --only=production USER node CMD ["dumb-init", "node", "server.js"]` しかし、これを行うと、秘密の npm トークンを含む .npmrc ファイルが Docker イメージ内に残ってしまいます。以下のように、後から削除することで改善を試みることができます。 RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && \ npm ci --only=production RUN rm -rf .npmrc しかし、今度は .npmrc ファイルが Docker イメージの別のレイヤーで利用できるようになりました。もし、このDocker イメージが公開されていたり、誰かが何らかの方法でアクセスできてしまうと、あなたのトークンは危険にさらされます。より良い改善策は以下のようになります。 RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && \ npm ci --only=production; \ rm -rf .npmrc ここで問題となるのは、Dockerfile 自体が秘密の npm トークンを含んでいるため、Dockerfile 自体をシークレットアセットとして扱う必要があることです。 幸いなことに、Docker はビルドプロセスに引数を渡す方法をサポートしています。 ARG NPM_TOKEN RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && \ npm ci --only=production; \ rm -rf .npmrc そして、以下のようにビルドします。 $ docker build . -t nodejs-tutorial --build-arg NPM_TOKEN=1234 この時点で全てが完了したと思われたでしょうが、残念ながらそうではありません。 セキュリティの世界では、当たり前のことが別の落とし穴になることもあるのです。 さて、何が問題なのでしょうか?このように Docker に渡されたビルド引数は、履歴ログに残ります。自分の目で確かめてみましょう。次のコマンドを実行してください。 $ docker history nodejs-tutorial 実行すると、次のように表示されます。 IMAGE CREATED CREATED BY SIZE COMMENT b4c2c78acaba About a minute ago CMD ["dumb-init" "node" "server.js"] 0B buildkit.dockerfile.v0 <missing> About a minute ago USER node 0B buildkit.dockerfile.v0 <missing> About a minute ago RUN |1 NPM_TOKEN=1234 /bin/sh -c echo "//reg… 5.71MB buildkit.dockerfile.v0 <missing> About a minute ago ARG NPM_TOKEN 0B buildkit.dockerfile.v0 <missing> About a minute ago COPY . . # buildkit 15.3kB buildkit.dockerfile.v0 <missing> About a minute ago WORKDIR /usr/src/app 0B buildkit.dockerfile.v0 <missing> About a minute ago ENV NODE_ENV=production 0B buildkit.dockerfile.v0 <missing> About a minute ago RUN /bin/sh -c apk add dumb-init # buildkit 1.65MB buildkit.dockerfile.v0 そこにシークレットのnpmトークンがあるのがわかりましたか?そこが問題です。 コンテナイメージのシークレットを管理するための優れた方法はありますが、今回はこの問題の緩和策としてマルチステージビルドを導入するとともに、ミニマムイメージを構築する方法を紹介します。 Node.jsのDockerイメージへのマルチステージビルドの導入 ソフトウェア開発における「関心事の分離」の原則と同じように、Node.js の Docker イメージを構築するためにも同じ考え方を適用します。Node.js の世界では、npm パッケージをインストールし、必要に応じてネイティブの npm モジュールをコンパイルします。これが最初のステージとなります。 Docker ビルドの第2ステージを表す2つ目のDocker イメージは、本番用のDockerイメージになります。この2番目で最後のステージは、実際に最適化してレジストリがあればそこに公開するイメージです。 build イメージと呼ばれる最初のイメージは廃棄され、クリーンアップされるまでビルドしたDocker ホストにぶら下がったままのイメージとして残されます。 これまでの進捗状況を表す Dockerfile の更新は次のとおりですが、2つのステージに分かれています。 # --------------> The build image FROM node:latest AS build ARG NPM_TOKEN WORKDIR /usr/src/app COPY package*.json /usr/src/app/ RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc && \ npm ci --only=production && \ rm -f .npmrc # --------------> The production image FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a RUN apk add dumb-init ENV NODE_ENV production USER node WORKDIR /usr/src/app COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules COPY --chown=node:node . /usr/src/app CMD ["dumb-init", "node", "server.js"] ご覧の通り、 build ステージでは、ネイティブの npm パッケージをコンパイルするために gcc (GNU Compiler Collection) などのツールが必要になるかもしれないので、大きなイメージを選びました。 第2ステージでは、 COPY 指示のための特別な表記があり、ビルド用 Docker イメージからnode_modules/フォルダをこの新しい本番 ベースイメージにコピーします。 また、今、 build 中間 Docker イメージに ビルド引数として NPM_TOKEN が渡されています。これは本番の Docker イメージには存在しないので、 docker history nodejs-tutorial コマンドの出力にはもう表示されていません。 9. Node.jsのDockerイメージから不要なファイルを排除する 不要なファイルや潜在的な機密ファイルで git リポジトリを汚染しないように、.gitignore ファイルを用意していますよね?同じことが Docker イメージにも当てはまります。 Docker には .dockerignore があり、これはDocker デーモンへの glob パターンマッチの送信をスキップするようになっています。ここでは、Docker イメージに何を入れているのか、理想的には避けたいファイルのリストを紹介します。 .dockerignore node_modules npm-debug.log Dockerfile .git .gitignore ご覧のとおり、 node_modules/ をスキップすることは実際には非常に重要です。なぜなら、もしこれを無視していなかったら、最初に行った単純な Dockerfile バージョンでは、ローカルの node_modules/ フォルダがそのままコンテナにコピーされてしまうからです。 FROM node@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a WORKDIR /usr/src/app COPY . /usr/src/app RUN npm install CMD "npm" "start" 実際、複数ステージの Docker ビルドを実践する際には、 .dockerignore ファイルを用意することがさらに重要になります。第2ステージの Docker ビルドがどのようなものか、以下おさらいとして。 # --------------> The production image FROM node:lts-alpine RUN apk add dumb-init ENV NODE_ENV production USER node WORKDIR /usr/src/app COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules COPY --chown=node:node . /usr/src/app CMD ["dumb-init", "node", "server.js"] .dockerignore を持つことの重要性は、2番目の Dockerfile ステージから COPY . /usr/src/app を行うと、ローカルの node_modules/ もDockerイメージにコピーされてしまいます。これは、node_modules/ 内の修正されたソースコードをコピーしてしまう可能性があるため、絶対避けるべきです。 さらに、ワイルドカードの COPY .を使用しているため、認証情報やローカル設定を含む機密ファイルを Docker イメージにコピーしている可能性もあります。 ここでの .dockerignoreファイルの要点は以下の通りです。 1.Docker イメージ内の node_modules/ の潜在的に変更されたコピーをスキップします。 2..env や aws.json ファイルの内容に含まれる認証情報が Node.js の Docker イメージに入ってしまうようなシークレットの暴露を防止します。 キャッシュ無効化の原因となるようなファイルを無視するため、Docker ビルドの高速化に貢献します。例えば、ログファイルが変更されたり、ローカル環境の設定ファイルが変更されたりすると、ローカルディレクトリをコピーした段階で、Docker イメージのキャッシュが無効になります。 10. シークレットをDockerビルドイメージにマウントする .dockerignore ファイルについて注意すべき点は、オール・オア・ナッシングのアプローチしかできず、Docker マルチステージビルドにおいてビルドステージごとにオン/オフを切り替えることはできないということです。 なぜそれが重要になるのでしょうか? 理想的には、ビルド段階で .npmrc ファイルを使用することが推奨されます。これは、プライベートな npm パッケージにアクセスするための秘密の npm トークンが含まれているため、必要になる場合があるためです。また、パッケージを取得するために、特定のプロキシやレジストリの設定が必要になることもあります。 つまり、 build ステージで .npmrc ファイルを利用できるようにしておくことは理にかなっていますが、本番イメージのための第2ステージでは全く必要ありませんし、シークレット npm トークンなどの機密情報が含まれている可能性があるため利用したくありません。 この .dockerignore の注意点を軽減する一つの方法は、ビルドステージで利用可能なローカルファイルシステムをマウントすることですが、もっと良い方法があります。 Docker は Docker secrets と呼ばれる比較的新しい機能をサポートしており、.npmrc で必要とされるケースに適しています。その仕組みを紹介します。 docker build コマンドを実行する際には、新しいシークレット ID を定義し、シークレットのソースとなるファイルを参照するコマンドライン引数を指定します。 Dockerfileでは、 RUN ディレクティブにフラグを追加して、本番 npm をインストールします。この npm は、シークレットIDで参照されたファイルを、目的の場所(ローカルディレクトリの .npmrc ファイル)にマウントします。 .npmrc ファイルはシークレットとしてマウントされ、Docker イメージにコピーされることはありません。 最後に、.npmrc ファイルを .dockerignore ファイルの内容に追加することを忘れないでください。そうすれば、ビルドイメージでも本番イメージでも、イメージには一切組み込まれなくなります。 これらがどのように機能するか見てみましょう。まず、更新された .dockerignore ファイルです。 .dockerignore node_modules npm-debug.log Dockerfile .git .gitignore .npmrc 次に、完全な Dockerfile と、 .npmrc マウントポイントを指定しながら npm パッケージをインストールするために更新された RUN ディレクティブです。 # --------------> The build image FROM node:latest AS build WORKDIR /usr/src/app COPY package*.json /usr/src/app/ RUN --mount=type=secret,mode=0644,id=npmrc,target=/usr/src/app/.npmrc npm ci --only=production # --------------> The production image FROM node:lts-alpine RUN apk add dumb-init ENV NODE_ENV production USER node WORKDIR /usr/src/app COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules COPY --chown=node:node . /usr/src/app CMD ["dumb-init", "node", "server.js"] そして最後に、Node.js の Docker イメージをビルドするコマンドです。 docker build . -t nodejs-tutorial --secret id=npmrc,src=.npmrc 注:Secrets は Docker の新機能であり、古いバージョンを使用している場合は、Buildkit を有効にする必要があるかもしれません。 $ DOCKER_BUILDKIT=1 docker build . -t nodejs-tutorial --build-arg NPM_TOKEN=1234 --secret id=npmrc,src=.npmrc まとめ これで、最適化された Node.js の Docker ベースイメージを作成するところまでが終わりました。 この最後のステップで、Node.js の Docker ウェブアプリケーションのコンテナ化に関するこのガイド全体が終了しました。パフォーマンスとセキュリティに関する最適化を考慮して、プロダクショングレードの Node.js の Docker イメージを確実に構築することができます。 フォローアップの資料をぜひご覧ください。 10 Docker image security best practices→参考翻訳記事 Docker for Java Developers: 5 things you need to know not to fail your security→参考翻訳記事 Node.js アプリケーション用に安全でパフォーマンスの高い Docker ベースイメージを構築したら、Snyk の無料アカウントでコンテナの脆弱性を見つけて修正しましょう。 最後まで、読んでいただきありがとうございました!!! Contents provided by: Jesse Casman, Fumiko Doi, Content Strategists for Snyk, Japan, and Randell Degges, Community Manager for Snyk Global
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

開発環境を構築する(WSL2 + Docker + VSCode - Remote Containers) 2022年1月版

PCを新調したので、開発環境を再構築。 以前も整理しようとした挙句にグチャグチャになってしまったので、ローカルではなくやはりコンテナ環境を使う方式へ。 どうせだったらVSCode Remote Container を使おうと。 環境はWindows11Homeです。VSCodeはインストール済みとします。 WSL2 のインストール コントロールパネル->プログラムと機能->Windowsの機能の有効化または無効化から、Linux用Windowsサブシステムをチェックを入れてインストールする(要再起動) Docker Desktop のインストール DockerHubよりインストーラーをダウンロードしてインストールします。 これによって、以下のモジュールがインストールされます * Dcoker Compose * Notary * Kubernetes * Credential Helper インストールにあたっての選択肢はそれほどなく、そのまま進めてしまっても問題ないかと思います。 一通りインストールが終わるとサインアウトを要求されるので実施します。 ログインしなおして進めていくと、カーネルアップデートを要求されるので指定リンクから実施します インストール後、DockerのRestartを実行後に下記ダイアログが表示されます。 Startをするとチュートリアルが開始されるので不要な人はスキップしましょう。 Ubuntu のインストール 今回、実行環境としてはUbuntuを使用することにしたのでこちらをインストールします。 インストールはMicrosoftStoreから検索して入手を押すだけ Ubuntuを開くとUbuntu用のユーザを作成する処理が動くので、ユーザ・パスワードを設定します VSCode の環境構築 Remote - Containers のインストール 何か忘れてるな、、と思ったら、肝心のRemote-Containersをインストールしていませんでした。 VSCode のプラグインを検索してインストールします Remote - WSL のインストール WSLと連携するために必要となるプラグインをインストールします ここまでで準備は完了。 WSL2上のUbuntuへ VSCodeから接続する WindowsTerminalを起動します 通常はPowerShellが起動されるので、横のプルダウンからUbuntuを選択します。 適当に今回のプロジェクトフォルダを作成し、docker-compose.ymlを作成してVSCodeを起動させます。 $ mkdir /home/<ユーザ>/workspace/sample $ cd /home/<ユーザ>/workspace/sample $ touch docker-compose.yml $ code. 起動したVSCode の左下が「WSL:Ubuntu-20.04」となっていて、WSL上で実行されたことが確認できます docker-compose.ymlの設定 起動したVSCodeを使って、docker-compose.ymlを編集。Nodeの環境を定義します。 (コンテナ名がsample-containerの場合) version: '3' services: node: image: node:lts container_name: node-container sample-container Remote - Containers でコンテナ起動 VSCode左下の緑のマークをクリックすると出てくるプロンプトから「Reopen in Container」を選択 ここで書きエラーが起きることがあります [56613857 ms] Start: Run in Host: docker version --format {{.Server.APIVersion}} [56613991 ms] The command 'docker' could not be found in this WSL 2 distro. We recommend to activate the WSL integration in Docker Desktop settings. For details about using Docker Desktop with WSL 2, visit: https://docs.docker.com/go/wsl2/ その場合はDockerDesktopの設定を変更しましょう 続いて「From 'Dcokerfile'」を選択 しばらくするとDocker上でVSCodeが再度立ち上がります。 VSCode上のTerminalを表示させるとちゃんと作成したプロジェクトフォルダとなっていることがわかります 終わりに ほぼ初期状態から構築したので、ずいぶんと手がかかってしまった感があるけど、これであとは開発対象によってDockerfileをいじればいいだけになったかな。 docker-composeも試してみたけど、こちらは正直まだうまくいかず。。。どこかでリベンジを。 いや、なんかローカルでしこしこ開発している時代から随分と変わりましたね。 開発環境をきちんと定義して、ポータビリティも持たせられる。いい話だ。 一方で、今動かしているのがWindows上なのかDocker上のものなのか。。。とか、この状態で進めていくと混乱しないのかな?が少し心配。 でもまぁ、次第に慣れていくでしょう。 参考 さくっとNode.js開発環境構築 (WSL2 + Docker-Compose + VSCode Remote - Containers) さくっとWSL2 + Docker + VSCode Remote - Containers でNode.jsが動く開発環境を構築する(devcontainer.jsonは自動生成する) WSL2 + Ubuntu + VSCodeでの開発環境構築 Windows ターミナル で WSL 2 の Ubuntu を使ってみる (+ Docker Desktop 統合) 仮想マシン プラットフォームの有効化と無効化
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for db failed: Name or service not known (SQL: SHOW FULL TABLES WHERE table_type = 'BASE TABLE')

Dockerで環境構築していた際につまづいたので、メモりました。 ご参考になれば幸いです。 概要 下記記事を参照してLaravel+React+MySQLの環境をDockerで作成しようとしたところ エラーが発生しました。 エラー内容 タイトルにある通り、以下のエラーが発生しました。 tarminal SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for db failed: Name or service not known (SQL: SHOW FULL TABLES WHERE table_type = 'BASE TABLE') DB(MySQL)への接続が上手くいっていないらしい... 調査結果 コンテナの起動確認 tarminal $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 737e1499b7c0 9df10d5fd4e9 "/entrypoint.sh mysq…" About a minute ago Exited (1) About a minute ago docker-laravel_db_1 d11753ef631f f5bc33c1bffa "/docker-entrypoint.…" 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp docker-laravel_web_1 1055b9270a37 198704a55e0c "docker-php-entrypoi…" 6 minutes ago Up 6 minutes 9000/tcp docker-laravel_app_1 dbコンテナだけSTATUSが「Exited」のままで起動していない ログ確認 tarminal $ docker logs <コンテナID> [Entrypoint] MySQL Docker Image 8.0.27-1.2.6-server [Entrypoint] Starting MySQL 8.0.27-1.2.6-server 2022-01-09T05:11:30.261390-00:00 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.27) starting as process 1 2022-01-09T05:11:30.264356-00:00 0 [ERROR] [MY-013276] [Server] Failed to set datadir to '/var/lib/mysql/' (OS errno: 13 - Permission denied) 2022-01-09T05:11:30.264532-00:00 0 [ERROR] [MY-010119] [Server] Aborting 2022-01-09T05:11:30.264761-00:00 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.27) MySQL Community Server - GPL. [Entrypoint] MySQL Docker Image 8.0.27-1.2.6-server [Entrypoint] Starting MySQL 8.0.27-1.2.6-server 2022-01-09T05:11:44.674545-00:00 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.27) starting as process 1 2022-01-09T05:11:44.677153-00:00 0 [ERROR] [MY-013276] [Server] Failed to set datadir to '/var/lib/mysql/' (OS errno: 13 - Permission denied) 2022-01-09T05:11:44.677246-00:00 0 [ERROR] [MY-010119] [Server] Aborting 2022-01-09T05:11:44.677499-00:00 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.27) MySQL Community Server - GPL. /var/lib/mysqlにデータを永続化したかったけど、マウントするところでアクセス権限がないよって怒られてますね。 解決策 ググったところ、下記記事が参考になりました。 この記事の中に下記の文言が記載されている つまり、マウントしたディレクトリに書き込めるのは、root か uid=1000 のユーザだけである。 my.cnfに記載されている動作ユーザの権限が「mysql」になっていたので、権限を「root」に変更してビルドしたところ無事解決!! tarminal Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (65.04ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (43.12ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (40.74ms) Migrating: 2019_12_14_000001_create_personal_access_tokens_table Migrated: 2019_12_14_000001_create_personal_access_tokens_table (68.47ms)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

サーバ移管をやってみた

既存のシステムを、新しいDockerのコンテナに移管してみる作業をやってみたので、その記録です。 今回の移管のゴール 細かい部分はあまり気にせず、とりあえず既存システムをコンテナに移して、動くところまでとします。 既存システムの環境 PHP 7.2.34 Laravel 5.7 MySQL 5.7 概要 ・Dockerコンテナを既存システムのディレクトリをマウントして起動し、PHP、MySQLをインストールします。 ・今回はPHPとMySQLは同一コンテナで行います。 コンテナを作成 docker run --rm --privileged --hostname <HOST_NAME> -it -v $(pwd):/app -p 8080:80 centos:7 /sbin/init -vオプションについて Qiita mysqlを使うときに、systemctlを使用します。 docker run --rm -it -v $(pwd):/app -p 8080:80 centos:7 bash のコマンドでDockerを起動すると、systemctlを使おうとしたとき、 Failed to get D-Bus connection: Operation not permittedのようなエラーが発生します。 そのため、オプションとして「Privileged(特権)」を設定し、起動スクリプトを「/sbin/init」にする必要があります。 privilegedオプションについて Qiita hostnameオプションについて ホスト名は、データベースに接続する際に使用します。既存システムで使用しているものと同名のものを指定してください。 コンテナを起動した際に、[root@<HOST_NAME> /]#となっていることを確認してください。 起動したら、コンテナをデタッチするか、別タブを開いて、コンテナに入ります。 ※ローカルのコンソール docker exec -it [コンテナID] /bin/bash /sbin/initで起動した場合、bashで起動した場合とは違い、exitではコンテナが停止しません。 停止したい場合は、shutdownコマンドを使用します。 shutdown コマンドは、マルチユーザーシステムを停止する場合に使用します。shutdown コマンドは、ログイン中のすべてのユーザーに警告メッセージを送信し、60 秒 (デフォルト) 待ってから、システムを停止してシングルユーザー状態にします。 システムの停止 shutdownコマンド実行時、タイムゾーンがUTCでわかりにくい場合は、下記コマンドで変更できます。(centOS7の場合) timedatectl set-timezone Asia/Tokyo Remi リポジトリの追加 yum -y install epel-release yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 参考 : CentOS 7 に PHP 7.2 を yum でインストールする手順 PHPのインストール yum -y install --enablerepo=remi-php72 install php 接続確認 Apacheを起動 systemctl start httpd ブラウザでアクセス 127.0.0.1:8080 centOSのテストページが表示されればOK。 ドキュメントルートを設定 ・ドキュメントルートがデフォルトでは、/var/www/html になっているので、変更します。 ・htaccessの設定を反映するために AllowOverrideにAllを設定します。 vi /etc/httpd/conf/httpd.conf - DocumentRoot "/var/www/html" + DocumentRoot "/app/public" - <Directory "/var/www/html"> + <Directory "/app/public"> - AllowOverride None + AllowOverride All # Allow open access: Require all granted </Directory> データベース設定 PDOをインストール yum -y install --enablerepo=remi,remi-php72 php-pdo mysqlのリポジトリを追加 yum -y localinstall https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm mysqlをインストール yum -y install mysql-community-server インストールが正常にできているか確認 mysqld --version バージョンが表示されればOK MySQLの設定 rootユーザに対して、権限設定を行っていきます。 ユーザにパスワードを設定する 環境変数MYSQLD_OPTSに認証機能を使用しない設定をセットする systemctl set-environment MYSQLD_OPTS="--skip-grant-tables" mysqlを起動 systemctl start mysqld.service パスワード無しでログインできます。 mysql -u root パスワードを更新します。 ※パスワードは、移管するシステムで使っているmysqlのパスワードと同じものを設定してください。 mysql > UPDATE mysql.user SET authentication_string = PASSWORD('root') WHERE User = 'root' AND Host = 'localhost'; mysql > FLUSH PRIVILEGES; ※権限情報をリロード mysql > quit 停止 systemctl stop mysqld MYSQLD_OPTS変数を解除 systemctl unset-environment MYSQLD_OPTS 起動 systemctl start mysqld.service これで、 セットしたパスワードでログインできます。 mysql -uroot -proot centos7 でmysqlのrootのパスワードを忘れた君へ 権限周りを設定する ※このままでは、 show databases;などのクエリを実行すると、 ERROR 1819 (HY000): Your password does not satisfy the current policy requirements というエラーが出るので、ポリシーに従ったパスワードを指定するか、下記のクエリを実行してパスワードを設定します。 mysql > SET GLOBAL validate_password_length=4;    # 許容する文字列の最低長さを変更 mysql > SET GLOBAL validate_password_policy=LOW; # ポリシーを変更(デフォルトはMEDIUM) パスワードを設定 mysql > ALTER USER 'root'@'localhost' IDENTIFIED BY 'root'; Mysql 5.7* パスワードをPolicyに合わせるとめんどくさい件について Qiita 現在のポリシーを確認して、表示されればOK。 mysql > SHOW VARIABLES LIKE 'validate_password%'; +--------------------------------------+-------+ | Variable_name | Value | +--------------------------------------+-------+ | validate_password_check_user_name | OFF | | validate_password_dictionary_file | | | validate_password_length | 4 | | validate_password_mixed_case_count | 1 | | validate_password_number_count | 1 | | validate_password_policy | LOW | | validate_password_special_char_count | 1 | +--------------------------------------+-------+ 外部からのアクセスできるようにする 現在のホストとユーザ情報を確認します。 mysql> SELECT Host, User from mysql.user; +-----------+---------------+ | Host | User | +-----------+---------------+ | localhost | mysql.session | | localhost | mysql.sys | | localhost | root | +-----------+---------------+ 上記のようにlocalhostしかない場合、外部からのアクセスができないので、追加します。 rootユーザにどこからでもアクセスできるようにします。 mysql > CREATE USER "root"@"%" IDENTIFIED BY "root"; rootユーザが全てのテーブルにアクセスできるようにします。 mysql > GRANT ALL ON *.* TO root@'%'; 再起動 systemctl restart mysqld.service 再起動すると、変更したポリシーはデフォルトに戻るので注意が必要です。 MySQLのドライバをインストール 現状では、おそらくphp artisan migrate:statusなどを行なうと、could not find driverというエラーが発生すると思います。 php -m | grep pdoを叩いてみると、mysqlが無いことが確認できると思います。 php -m | grep pdo >>> pdo_sqlite mysqlのドライバはphp-mysqlndなので、インストールします。 yum -y install --enablerepo=remi,remi-php72 php-mysqlnd php -m | grep pdo >>> pdo_mysql >>> pdo_sqlite これで、could not find driverエラーは無くなると思います。 MySQLのログイン設定 インセキュアエラーを解決するため、mysqlのログイン時にパスワードをコンソールに入力しなくて良いように設定します。 my.cnfファイルを編集します。 vi /etc/my.cnf 下記を追加します。 + [client] + user = root + password = root このファイルの情報を使用してログインできるように以下のコマンドを実行します。 mysql --defaults-extra-file=/etc/my.cnf これで、mysqlにログインできたと思います。 次回以降は、 mysql のみでログインできます。 データベースを作成 既存システムで使用しているデータベースと同名のデータベースを作成します。 mysql > CREATE DATABASE <DB_NAME> dumpファイルを取り込む 既存システムを移管する場合、現時点でDBにデータがあると思うので、そのデータを引き継ぎます。 用意したdumpファイルは、以下のディレクトリにあると仮定します。※適宜読み替えてください。 ~/dump/dump.sql # ローカル環境のパス dockerコンテナ内にdumpファイルをコピーします。 コピーする際に、コピー先のディレクトリが必要になるので、あらかじめ作成しておきます。 mkdir /dump コピーを行います。 ※ローカルのコンソール docker cp ~/dump/dump.sql mysql:/dump/dump.sql これでコピーは完了です。 dumpファイルを反映する ローカルからコンテナにコピーしたdumpファイルをmysqlに反映します。 mysql <DB_NAME> < /dump/dump.sql 反映されたか確認します。 mysql mysql > use <DB_NAME> Database changed mysql > show tables; テーブルが作成されていればOK。 マイグレート マイグレーションが必要な場合は実行します。 cd /app php artisan migrate マイグレーションを実行できればOK。 サーバを再起動 systemctl restart httpd 正常にアクセスできればOK。 127.0.0.1:8080 最後に このあたりの経験は浅いので、アドバイスなどあればいただけるとありがたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Minioを用いてAWSアカウントなしでS3接続(javaSDK)を確認する方法

概要 この記事では、AWSのアカウントなしでもAWS S3 接続を確認できる方法を記事にしてみました。 Minio自体は、AWS S3 と互換性があるマルチクラウドオブジェクトストレージのOSSとして知られています。 現場の業務上 S3 に対してJavaを用いて接続する必要があり自宅で無料で接続確認がしたくてminioを採用しました。 使用方法をwebで調べたのですが、出てくるのはdockerを用いて簡単に構築することができることやMinioが提供しているライブラリを用いて接続する方法しかなく、AWS SDKで接続する方法が見つからなかったので今回挑戦し成功したので記事にしてみました。 minioって何?っていう方は以下の記事や公式のサイトを見ると理解できると思います。 https://min.io/ https://dev.classmethod.jp/articles/s3-compatible-storage-minio/ aws s3って何?という方は以下の記事や公式のサイトを見ると理解できると思います。 https://aws.amazon.com/jp/s3/ https://business.ntt-east.co.jp/content/cloudsolution/column-try-43.html 必要なもの dockerDesktop eclipse aws SDK jarファイル 方法 以下の記事より、dockerDesktopよりminioの環境を構築する https://dev.classmethod.jp/articles/s3-compatible-storage-minio/ 以下のサイトを参考にソースコードを作成しました。 https://docs.min.io/docs/how-to-use-aws-sdk-for-java-with-minio-server.html package minioS3; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; public class Main { private static String bucketName = "testbucket"; private static String keyName = "hosts"; //指定したい自身のパソコン内のパスを記入する 今回はホストファイルを指定して簡易動作確認します。 private static String uploadFileName = "/etc/hosts"; public static void main(String[] args) throws IOException { //YOUR-ACCESSKEYID YOUR-SECRETACCESSKEYにminioに指定した値を入れる AWSCredentials credentials = new BasicAWSCredentials("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setSignerOverride("AWSS3V4SignerType"); //EndpointにMinioで指定した値を入れる リージョンの値はそのままで問題ないです。 AmazonS3 s3Client = AmazonS3ClientBuilder .standard() .withEndpointConfiguration( new AwsClientBuilder.EndpointConfiguration("http://localhost:9000", Regions.US_EAST_1.name())) .withPathStyleAccessEnabled(true) .withClientConfiguration(clientConfiguration) .withCredentials(new AWSStaticCredentialsProvider(credentials)) .build(); try { System.out.println("Uploading a new object to S3 from a file\n"); File file = new File(uploadFileName); // Upload file s3Client.putObject(new PutObjectRequest(bucketName, keyName, file)); // Download file GetObjectRequest rangeObjectRequest = new GetObjectRequest(bucketName, keyName); S3Object objectPortion = s3Client.getObject(rangeObjectRequest); System.out.println("Printing bytes retrieved:"); displayTextInputStream(objectPortion.getObjectContent()); } catch (AmazonServiceException ase) { System.out.println("Caught an AmazonServiceException, which " + "means your request made it " + "to Amazon S3, but was rejected with an error response" + " for some reason."); System.out.println("Error Message: " + ase.getMessage()); System.out.println("HTTP Status Code: " + ase.getStatusCode()); System.out.println("AWS Error Code: " + ase.getErrorCode()); System.out.println("Error Type: " + ase.getErrorType()); System.out.println("Request ID: " + ase.getRequestId()); } catch (AmazonClientException ace) { System.out.println("Caught an AmazonClientException, which " + "means the client encountered " + "an internal error while trying to " + "communicate with S3, " + "such as not being able to access the network."); System.out.println("Error Message: " + ace.getMessage()); } } private static void displayTextInputStream(InputStream input) throws IOException { // Read one text line at a time and display. BufferedReader reader = new BufferedReader(new InputStreamReader(input)); while (true) { String line = reader.readLine(); if (line == null) break; System.out.println(" " + line); } System.out.println(); } } まとめ awsは素晴らしいサービスですが、一歩間違うと大金を支払う可能性が出てくるので使うのが怖いですよね。 minioは他にも工夫すれば、スクレイピングの情報を溜めておくのに使えたりサイトのページとして使えるので応用を効かせると 夢が広がります。 今回、人生で初めてQiita投稿しました。 今後も、現場での知識や気になった技術などの投稿をしていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Batch でゲノムマッピングをしてみる

初めに BWA を Centos イメージにインストールして簡単に AWS Batch で動かしてみます。リファレンスファイルや FASTQ ファイルは S3 バケットに保存しておき、Batch ジョブでダウンロードします。 Docker イメージの作成 Centos イメージに BWA、AWS CLI v2 をインストールするイメージを作成します。 Dockerfile FROM centos RUN yum install -y git make gcc zlib-devel unzip \ && git clone https://github.com/lh3/bwa.git \ && cd bwa \ && make \ && cp bwa *.pl /usr/bin \ && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \ && unzip awscliv2.zip \ && ./aws/install -i /usr/local/aws-cli -b /usr/bin \ && rm -f awscliv2.zip COPY run_bwa.sh /bwa/run_bwa.sh CMD sh /bwa/run_bwa.sh こちらはコンテナで実行するシェルスクリプトです。BWA でマッピングを行うためのコマンドを記述します。 run_bwa.sh echo 'mapping START' mkdir /fa_files mkdir /fq_files mkdir /sam_files # リファレンスファイルのダウンロード aws s3 cp s3://my-gwf-bucket/fa_files/chr5.fa /fa_files/chr5.fa # インデックスの作成 bwa index /fa_files/chr5.fa # FASTQ ファイルをダウンロード aws s3 cp s3://my-gwf-bucket/fq_files/paired_1.fq /fq_files/paired_1.fq aws s3 cp s3://my-gwf-bucket/fq_files/paired_2.fq /fq_files/paired_2.fq # マッピング bwa mem -t 8 -o /sam_files/output.sam /fa_files/chr5.fa /fq_files/paired_1.fq /fq_files/paired_2.fq # 作成した SAM ファイルをアップロード aws s3 cp /sam_files/output.sam s3://my-gwf-bucket/sam_files/output.sam Docker イメージが完成したら ECR に Push します。 AWS Batch の手順 コンピューティング環境の作成 「マネージド型」を選択し、サービスロールは 「Batch service-linked role」 を選択します。 「オンデマンド」を選択し、最小 vCPU 、最大 vCPU、必要な vCPU はそれぞれデフォルトのままにします。 こちらもデフォルトのままにします。 EC2 設定のところで、矢印で示した「設定の追加」をクリックします。イメージタイプには「Amazon Linux2」を選択します。なぜか空白のままですが、問題ありません。 その後「コンピューティング環境の作成」をクリックします。 ジョブ定義の作成 「EC2」を選択し、ジョブの試行は「1」を入力します。 コンテナプロパティではイメージに ECR の URI を入力します。コマンドは Dockerfile の CMD で指定したコマンド sh /bwa/run_bwa.sh を入力します。 vCPU は「8」、メモリはデフォルトの「2048」を指定します。ジョブロールには S3 バケットに対するダウンロード・アップロード権限を付与したロールを指定します。実行ロールには ECR からイメージを Pull できる権限を付与したロールを指定します。 その後「作成」をクリックします。 ジョブキューの作成 ジョブキュー名を入力します。 コンピューティング環境の作成 で作成したコンピューティング環境を選択します。 その後「作成」をクリックします。 ジョブの送信 作成したジョブ定義から「新しいジョブを送信」をクリックします。 ジョブ定義、ジョブキューを指定します。 その後「送信」をクリックします。 注意点 ジョブの vCPU(コンテナに割り当てられる vCPU)が、コンピューティング環境で指定した EC2 インスタンスタイプの CPU を超えていると ジョブのステータスが RUNNABLE から動かなくなります。この記事ではインスタンスタイプを Optional にしていますので、任意の vCPU に対して AWS Batch により適切なインスタンスが起動し、ジョブは RUNNABLE で止まることはありません。 ジョブが成功したことを確認する ジョブ送信後、ECS でコンテナタスクが実行されます。 インスタンスが起動しています。 タスクが終了するとインスタンスは削除されます。 ログを確認して、タスクが正常に完了したことを確認します。 S3 バケットに SAM ファイルがアップロードされていることを確認します。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker on WSL2 without Docker Desktopを構築し、VSCode Remote-Containersで接続する

はじめに Docker Desktopが既に有償化され、猶予期間も2022年1月末までとなっています。 without Docker Desktopな環境を構築してみて、改めてDocker Desktopの素晴らしさを実感しましたので、WindowsでDockerを使う人は基本的にDocker Desktopを使用する事をお勧めします。 有償化対象だけどどうしても支払いが難しい(Docker Desktopが使えない)という方のみ、以下をお読み下さい。 なお、2021年11月に行った手順を書き起こしています。 投稿時点で情報が古くなっている点、ご了承ください。 この記事を読んで出来ること Windwos上で、Docker Desktopに頼らずにDockerを使用できる コマンドプロンプト上でdockerコマンドを使用できる Windows上のVSCodeからDockerコンテナに接続できる この記事を読んでも出来ないこと Dockerサービスの自動起動はしない 頑張れば自動起動もできるらしいですが、私はWindowsを起動する度に手動でDockerサービスを起動させてます。 0.前提条件 WSL2でUbuntu 20.04がデフォルトのディストリビューションとして使用できること コマンドプロンプトでwsl -l -vと打ってもらって、以下のように出力されればOKです。 C:\Users\user> wsl -l -v NAME STATE VERSION * Ubuntu-20.04 Running 2 STATEはStoppedでも良いですし、Ubuntu-20.04以外のディストリビューションが入っていても構いませんが、VERSIONが2のUbuntuに*が付いているようにして下さい。 この条件を満たしていない方は、以下Microsoft公式ドキュメントを参考に条件を整えて下さい。 https://docs.microsoft.com/ja-jp/windows/wsl/install VSCodeと拡張機能:Remote-WSL, Remote-containersがインストールされていること Dockerを実行するだけなら無くてもいいのですが、本稿の価値は半減します。 プロキシ環境下にいる場合、Ubuntu 20.04のプロキシ設定がされていること bashの環境変数(~/.bashrc)とaptの設定(/etc/apt/apt.conf.d/xxxx)あたりが必要です。 以下の記事などを参考に、必要な設定をして下さい。 https://qiita.com/sachioksg/items/289e40d69382b1d09811 1.Dockerのインストール WSL内での作業です。 基本的には公式の手順(リポジトリを使う場合)に沿って行います。 https://docs.docker.com/engine/install/ubuntu/ https://docs.docker.com/engine/install/linux-postinstall/ リポジトリのセットアップ $ sudo apt-get update $ sudo apt-get install 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 $ echo \ "deb [arch=$(dpkg --print-architecture) 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エンジンの起動(※ここだけ公式手順にない) ※dockerエンジンの起動は環境構築時だけでなく、Windowsを起動する毎に行う必要があります。 $ sudo service docker start プロキシ環境下の方はプロキシ設定 /etc/default/dockerで設定できるようです。 2.Docker Composeのインストール 不要な方はこの章を読み飛ばして下さい。 WSL内での作業です。 Docker Composeも公式の手順でインストールします。 https://docs.docker.com/compose/install/ v2も出ていますが、2022年1月現在、v1.29.2がstableだそうですので、それをインストールします。 $ curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o ~/docker-compose $ sudo cp ~/docker-compose /usr/local/bin/ $ sudo chmod +x /usr/local/bin/docker-compose 3.Windows上でdockerコマンドを使えるようにする Windows上で以下のdocker.cmdというバッチファイルを作成し、パスを通します(Windowsの環境変数Pathに追加)。 docker.cmd @echo off wsl -- docker %* 同様に、以下のdocker-compose.cmdというバッチファイルを作成し、パスを通します。 docker-compose.cmd @echo off wsl -- docker-compose %* これで環境構築は完了です。 コマンドプロンプトでdocker run hello-worldを実行し、DockerからHelloしてもらえたら成功です。 C:\Users\user> docker run hello-world 4.VSCodeのRemote-containersを使ってみる Docker on WSL2で実行中のコンテナに、Windows上のVSCodeから接続します。 なんでもいいのでコンテナを走らせておいて下さい。 Remote-WSLなVSCodeを開く WSL内で"code"コマンドをオプション無しで実行するか、コマンドプロンプトで"wsl code"を実行するか、(通常の)VSCodeのCommand Paletteから"Remote-WSL: New WSL Window"を実行します。 新たなVSCodeウィンドウが開いて、左下に"><"ではなく">< WSL: Ubuntu-20.04"と表示されていればOKです。 Remote-containersなVSCodeを開く 上記Remote-WSLなVSCodeのCommand Paletteから"Remote-containers: Attach to Running Container..."を選択し、所望のコンテナを選択します。 さらに別のVSCodeウィンドウが開いて、左下に">< Container xxxx"と表示されていれば成功です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker内部から外部ネットワークへ接続できないようにしたい

docker内部から外部ネットワークへの通信が発生することが望ましくないケースがあるときに使う備忘メモ 最初からネットワーク遮断する場合 最初からネットワーク遮断する場合はdocker起動時に--network=noneオプションを付ける方法が良いと思われる ネットワークから遮断したDockerコンテナを立ち上げたい --network=noneオプションを付ける $ docker run -it --network=none ubuntu:18.04 ## 上記の後、apt updateは失敗する(意図通り、外部ネットワークへ接続できないようにできている) $ apt update -y Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' ... W: Some index files failed to download. They have been ignored, or old ones used instead. --network=noneオプションを付けない $ docker run -it ubuntu:18.04 ## 上記の後、apt updateは成功する $ apt update -y Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] ... Fetched 24.0 MB in 7s (3525 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date. 途中からネットワーク遮断する場合 途中からネットワーク遮断する場合はdocker network disconnectを使う方法が良いと思われる コンテナのネットワーク 例 docker network disconnect bridge ${CONTAINER_NAME} # 普通に起動させると apt update -y が成功する $ docker run -it --name ubuntu ubuntu:18.04 cat & $ docker exec -it ubuntu bash $ apt update -y Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] ... Fetched 24.0 MB in 7s (3525 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date. # docker network disconnect すると、意図通り、外部ネットワークへ接続できないようになる $ exit $ docker network disconnect bridge ubuntu $ docker exec -it ubuntu bash $ apt update -y Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' ... W: Some index files failed to download. They have been ignored, or old ones used instead. 尚、ネットワークに繋げるにはdocker network connectを使う 例 docker network connect bridge ${CONTAINER_NAME} 参考 ネットワークから遮断したDockerコンテナを立ち上げたい Docker network 概論 docker network disconnectコマンドの使い方(実例付) コンテナのネットワーク コンテナを切断(disconnect)し、ネットワークからコンテナを取り外せます。切断にはネットワーク名とコンテナ名を指定します。あるいは、コンテナ ID も使えます。この例では、名前を指定する方が速いです。 $ docker network disconnect bridge networktest
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】Debezium でデータソース (DBなど) の変更を検知して Consumer で受け取るまで。

概要 前回の続きです。 今回は Consumer で変更内容を受け取って、メッセージを出力するところまでのメモです。 docker-compose 何度も起動するのが面倒なので docker-compose にしました。 前回のチュートリアルで docker run していた内容を docker-compose に書き直した感じです。 ポイント debezium_network という名前の Docker ネットワークにすべて配置します。 version がちょっと古いのは会社の docker のバージョンがちょっと古いからです。v3 を使用すると network 周りの書き方などがちょっと変わるみたいです。 docker-compose.yaml version: "2.4" services: zookeeper: container_name: "zookeeper" image: "debezium/zookeeper:1.8" networks: - "debezium_network" ports: - "2181:2181" - "2888:2888" - "3888:3888" kafka: container_name: "kafka" image: "debezium/kafka:1.8" depends_on: - "zookeeper" networks: - "debezium_network" ports: - "9092:9092" environment: - "ZOOKEEPER_CONNECT=zookeeper:2181" mysql: container_name: "mysql" image: "debezium/example-mysql:1.8" networks: - "debezium_network" ports: - "3306:3306" environment: - "MYSQL_ROOT_PASSWORD=debezium" - "MYSQL_USER=mysqluser" - "MYSQL_PASSWORD=mysqlpw" connect: container_name: "connect" image: "debezium/connect:1.8" depends_on: - "zookeeper" - "kafka" - "mysql" networks: - "debezium_network" ports: - "8083:8083" environment: - "BOOTSTRAP_SERVERS=kafka:9092" - "GROUP_ID=1" - "CONFIG_STORAGE_TOPIC=my_connect_configs" - "OFFSET_STORAGE_TOPIC=my_connect_offsets" - "STATUS_STORAGE_TOPIC=my_connect_statuses" networks: default: external: name: "bridge" debezium_network: name: debezium_network driver: "bridge" 起動後の KafkaConnect へのDebeziumMySQLコネクタの登録 はとりあえず手動のままで $ curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" localhost:8083/connectors/ -d '{ "name": "inventory-connector", "config": { "connector.class": "io.debezium.connector.mysql.MySqlConnector", "tasks.max": "1", "database.hostname": "mysql", "database.port": "3306", "database.user": "debezium", "database.password": "dbz", "database.server.id": "184054", "database.server.name": "dbserver1", "database.include.list": "inventory", "database.history.kafka.bootstrap.servers": "kafka:9092", "database.history.kafka.topic": "dbhistory.inventory" } }' 余談 立ち上げたコンテナを一括で終了させるには、滅びの呪文を使うと楽です。 Consumer 準備 データソースに変更が加わったら、 debezium が検知して kafka に変更内容をキューとして登録します。 そのキューに登録された内容を使用して何らかの処理をおこないます。 今回は手っ取り早く、 nodejs でキューが登録されたら、その内容をコンソールに表示するだけのアプリケーションを作ります。 kafka-node というパッケージを使用しました。 package.json { "name": "test-kafka-node", "version": "1.0.0", "description": "", "main": "index.ts", "scripts": { "start": "ts-node index.ts" }, "author": "", "license": "ISC", "dependencies": { "kafka-node": "^5.0.0", "ts-node": "^10.4.0" }, "devDependencies": { "@types/kafka-node": "^3.0.0" } } index.ts import kafka from "kafka-node"; const client = new kafka.KafkaClient({ kafkaHost: "kafka:9092", }); const consumer = new kafka.Consumer( client, [{ topic: "dbserver1.inventory.customers"}], // ★customers テーブルに変更を加える予定 { autoCommit: true, fromOffset: true, groupId: "consumer1", } ); consumer.on("message", function (message) { console.log(message); }); console.log("ready."); Dockerfile も作成しておきます。 こちらからほぼ丸パクリさせていただきました。 # OS: Debian Buster # Node.js: 14.4.0 FROM node:14.4.0-buster # Create app directory WORKDIR /usr/src/app # Install app dependencies (package.json and package-lock.json) COPY package*.json ./ RUN npm install # Bundle app source (server.js) COPY . . # Listen port EXPOSE 8080 # Run Node.js CMD [ "npm", "run", "start" ] Consumer 起動 同じネットワーク内で起動させたいので --network debezium_network を指定します。 $ docker image build -t test-kafka-node:latest . $ docker run -it --rm --name consumer --network debezium_network test-kafka-node 変更を加える 今回は mysql のコンテナに直接入って、Update文を実行してみます。 $ docker exec -it mysql bash root@d8382f3c83e8:/# mysql -uroot -pdebezium mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.27 MySQL Community Server - GPL Copyright (c) 2000, 2021, Oracle and/or its affiliates. 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> use inventory; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> UPDATE customers SET first_name='Anne99999' WHERE id=1004; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 上記のように customers テーブルに変更を加えると、 customers テーブルに変更が入る debezium により kafka にキューが登録される kafka に入ったキューを nodejs の consumer が拾って console.log(message) が実行されます。 実際に cunsumer のコンテナで message が確認できます。 message から変更内容が取得できるので、その内容をもとに Lambda を叩くなり、リードモデルにデータを挿入したり、メール送ったりと、後はどうにでもなりそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む