Dockerデプロイメントを試してみましょう

Dockerデプロイメントを試してみましょう

[[416152]]

この記事はWeChatの公開アカウント「Sea Monster Who Writes Code」から転載したもので、著者はSea Monster Who Writes Codeです。この記事を転載する場合は、コードを書いているSea Monsterの公式アカウントまでご連絡ください。

序文

多くの人が Docker のデプロイメントについて頭を悩ませていると思います。私も同じです。

最近、私は非常に興味深い現象を発見しました。ある技術を習得したいと思って習得した後、別の技術を習得しなければならない問題が発生すると、その人がそれまでどれだけ熱心に熱心に学習していたとしても、この時点で諦めてしまう可能性が 99% あります。私はこの現象を「学習の窓」と呼びたいと思います。

多くの人にとって、Web サイトの作成と Vue.js の学習は「学習の窓口」となります。この「学習期間」を過ぎると、彼らはもう学習したくなくなります。「たくさん学んだのに、なぜ最後にデプロイメントを学習しなければならないのか?」

したがって、この記事では Docker のデプロイメントに関するいくつかの点について説明します。

必要

国際的な慣行によれば、私たちはいくつかのことだけを完了する非常に単純な要件から始めます。

ToDo リストを表示 + ToDo を追加

ウェブサイト訪問を記録する

上記は、これ以上ないほど古典的な Todo リスト アプリケーションです。

要件を分析します。ToDo リストはデータベースを使用して完了する必要があり、Web サイト訪問の記録は高速読み取りキャッシュを使用して完了する必要があります。

技術の選択

現在、私のフロントエンドテクノロジースタックは React.js なので、フロントエンドでは React.js を使用しています。

Express には独自のスキャフォールディングがあるため、バックエンドでは Express が使用されます。

データベースに関しては、M1 Mac を使用しているため、MySQL イメージをプルすることができず、代わりに一時的に MariaDB を使用しています。

キャッシュは誰もがよく知っているので、redis を使用してキャッシュを実行します。

フロントエンド実装

フロントエンドの実装は非常にシンプルで、リクエストの送信には axios が使用されます。

  1. インターフェースTodo {
  2. id: 番号;
  3. タイトル: 文字列;
  4. ステータス: 'todo' | '終わり' ;
  5. }
  6.  
  7. 定数http = axios.create ({
  8. ベースURL: 'http://localhost:4200'
  9. })
  10.  
  11. 定数App = () => {
  12. const [newTodoTitle, setNewTodoTitle] = useState<string>( '' );
  13. 定数[ count ,setCount] = useState(0);
  14. const [todoList, setTodoList] = useState<Todo[]>([]);
  15.  
  16. // ToDo を追加
  17. const addTodo = 非同期() => {
  18. http.post( '/todo' , {を待つ
  19. タイトル: newTodoTitle、
  20. ステータス: 'todo'
  21. })
  22. fetchTodoList() を待機します。
  23. }
  24.  
  25. // 訪問回数を取得し、訪問を追加する
  26. const fetchCount = 非同期() => {
  27. http.post( '/count' ) を待ちます。
  28. const { データ } = http.get( '/count' ) を待機します。
  29. データにカウントを設定します。
  30. }
  31.  
  32. // ToDoリストを取得する
  33. const fetchTodoList = 非同期() => {
  34. const { data } = http.get( '/todo' ) を待機します。
  35. todoList を設定します。
  36. }
  37.  
  38. 使用効果(() => {
  39. fetchCount() を実行します。それから();
  40. TodoList() を取得します。それから();
  41. }, []);
  42.  
  43. 戻る
  44. <div className= "アプリ" >
  45. <header>ウェブサイト訪問数: { count }</header>
  46.  
  47. <ul>
  48. {todoList.map(todo => (
  49. <li key ={todo.id}>{todo.title} - {todo.status}</li>
  50. ))}
  51. </ul>
  52.  
  53. <div>
  54. <input value={newTodoTitle} onChange={e => setNewTodoTitle(e.target.value)} type= "text" />
  55. <button onClick={addTodo}>送信</button>
  56. </div>
  57. </div>
  58. );
  59. }

バックエンド実装

バックエンドは少し面倒で、解決すべき問題は次のとおりです。

  • クロスドメイン
  • データベース接続
  • Redis 接続

まず main.ts でルーティングを構成します。

  1. var cors = require( 'cors' )が必要です
  2.  
  3. var indexRouter = require( './routes/index' );
  4. var usersRouter = require( './routes/count' );
  5. var todosRouter = require( './routes/todo' );
  6.  
  7. var app = express();
  8.  
  9. // クロスドメインを解決する
  10. app.use(cors());
  11.  
  12. //ビジネスルーティング
  13. app.use( '/' 、インデックスルーター);
  14. app.use( '/count' 、 usersRouter);
  15. app.use( '/todo' , todosRouter);
  16.  
  17. ...
  18.  
  19. モジュールをエクスポートします。

トラフィック ルーティングでは、高速な読み取りと書き込みを実現するために Redis が必要です。

  1. 定数 express は require( 'express' ) を必要とします。
  2. const Redis = require( "ioredis" );
  3.  
  4. 定数ルーター = express.Router();
  5.  
  6. // Redisに接続
  7. const redis = 新しい Redis({
  8. ポート: 6379、
  9. ホスト: "127.0.0.1"
  10. });
  11.  
  12. router.get( '/' , async (req, res, next ) => {
  13. const count = Number(redis.get( 'myCount' ) を待機) || 0;
  14.  
  15. res.json({ myCount: count })
  16. });
  17.  
  18. router.post( '/' , 非同期(req, res) => {
  19. const count = Number(redis.get( 'myCount' ) を待機します);
  20. redis.set ( 'myCount' , count + 1);を待ちます。
  21. res.json({ myCount: count + 1 })
  22. })
  23.  
  24. モジュール.exports = ルーター;

todo ルートは、sequelize ライブラリを使用してデータベースに接続し、初期化します。

  1. const { Sequelize, DataTypes} = require( 'sequelize' );
  2. 定数 express = require( "express" );
  3.  
  4. 定数ルーター = express.Router();
  5.  
  6. // データベースに接続する
  7. const sequelize = 新しい Sequelize({
  8. ホスト: 'localhost'
  9. データベース: 'docker_todo'
  10. ユーザー名: 'root'
  11. パスワード: '123456'
  12. 方言: 'mariadb'
  13. });
  14.  
  15. // todoモデルを定義する
  16. const Todo = sequelize.define( 'Todo' , {
  17. id: {
  18. タイプ: Sequelize.INTEGER
  19. 自動増分: true
  20. プライマリキー: true  
  21. },
  22. タイトル: { タイプ: DataTypes.STRING },
  23. ステータス: { タイプ: DataTypes.STRING }
  24. }, {});
  25.  
  26. // データベース構造を同期する
  27. sequelize.sync({ force : true })を実行します。すると(() => {
  28. console.log( '同期されました' );
  29. });
  30.  
  31. router.get( '/' , 非同期(req, res) => {
  32. // ToDoリストを取得する
  33. todoList を待機します。
  34. res.json({todoList});
  35. })
  36.  
  37. router.post( '/' , async (req, res, next ) => {
  38. const { タイトル、ステータス } = req.body;
  39.  
  40. // ToDoを作成する
  41. const newTodo = Todo を待機します。作成する({
  42. タイトル、
  43. ステータス: ステータス || 「todo」
  44. });
  45.  
  46. res.json({todo: newTodo }) は、
  47. });
  48.  
  49. モジュール.exports = ルーター;

ローカルで実行

本来、次のコマンドを使用してローカル アプリケーションを実行できます。

  1. # フロントエンド
  2. cd クライアント && npm run 開始
  3.  
  4. # 後部
  5. cd サーバー && npm 実行開始

しかし、ローカルに mariadb と redis がないので、少し困難です。

コンテナを起動する

以前は、通常、次のコマンドを使用して、Mac に mariadb と redis をインストールしていました。

  1. brew インストール mariadb
  2.  
  3. brew redis をインストール

その後、プロジェクトをローカルで実行する前に、コンピューター上で設定 (ユーザー名、パスワードなど) を行う必要があり、非常に面倒です。そして、設定が間違っていたら、再インストールしなければなりません。 。 。

Docker の機能の 1 つは、mariadb と redis を異なるイメージにパッケージ化し、DockerHub を使用して統合管理することです。 Docker を使用すると、サービスをすばやく構成できます。

以前は、コンピューターにインストールできる MySQL は 1 つだけでした。これで、8 つの MySQL コンテナ (異なるポートを使用) を同時に実行できるようになりました。必要なものを削除したりインストールしたりできます。疑わしい場合は、まずコンテナを再起動してください。再起動しても問題が解決しない場合は、イメージを使用してコンテナを構築します。ビルドが機能しない場合は、最新のイメージをプルして再度ビルドしてください。とてもかっこいいですね。

では、早速Redisを起動してみましょう。

  1. docker run --name docker-todo-redis -p 6379:6379 -d redis  

次に、mariadb を起動します。

  1. docker run -p 127.0.0.1:3306:3306 --name docker-todo-mariadb -e MARIADB_ROOT_PASSWORD=123456 MARIADB_DATABASE=docker_todo -d mariadb  

パラメーター -p はポート マッピング: ローカル マシン: コンテナー、-e は環境変数を指定し、-d はバックグラウンド実行を意味することを説明します。

もう一度実行します:

  1. # フロントエンド
  2. cd クライアント && npm run 開始
  3.  
  4. # 後部
  5. cd サーバー && npm 実行開始

http://localhost:3000 でページを見ることができます:

大丈夫みたいですよ〜

docker-compose

もし今、マシンが与えられたら、それをどのように展開するか想像してみてください。最初に上記の 2 つの docker コマンドを実行し、次に以下の 2 つの npm コマンドを実行する必要があります。面倒だ。

ワンクリックでmariadbコンテナとredisコンテナを起動できますか?ここで docker-compose.yml が登場します。dev-docker-compose.yml ファイルを作成します。

  1. バージョン: '3'  
  2. サービス:
  3. マリアdb:
  4. 画像: mariadb
  5. コンテナ名: 'docker-todo-mariadb'  
  6. 環境:
  7. MARIADB_ROOT_パスワード: '123456'  
  8. MARIADB_DATABASE: 'docker_todo'  
  9. ポート:
  10. - '3306:3306'  
  11. 再起動: 常に
  12. レディス:
  13. 画像: redis
  14. コンテナ名: 'docker-todo-redis'  
  15. ポート:
  16. - '6379:6379'  
  17. 再起動: 常に

この yml ファイルに記述されている内容は、実際には上記の 2 つの docker コマンドと同等です。利点は2つあります。

  • 耐えられないほど長いコマンドのリストを書く必要はありません。
  • docker-compose.yml ファイルにデプロイメント コマンドを書き留めます。 Q: どのように展開しますか? A: docker-compose.ymlを見てください
  • ワンクリックで関連サービスを表示

今後は、ローカル サービスを実行するときに、mariadb と redis をワンクリックで起動できます。

  1. docker-compose -f dev-docker-compose.yml アップ -d

Dockerファイル

しかし、本番環境ではこれら 2 つの npm コマンドを毎回実行するのは依然として面倒です。これら 2 行も docker-compose に統合できますか?

注: 通常の開発プロセスでは、npm run build を使用して本番環境でアプリケーションをビルドし、ビルドされた JS を実行します。プロセスを簡略化するために、npm run start を例として使用します。

docker-compose はイメージを通じてコン​​テナを作成するので、React アプリと Express アプリも 2 つのイメージにパッケージ化して、docker-compose を使用して個別にコンテナを作成してもよいのではないでしょうか。

簡単に言えば、コンテナの構築は「CICD またはビルド パイプライン」と呼ばれることが多いのですが、この「パイプライン」の鍵となるのは npm run start 1 つだけです。 「パイプライン」を記述するファイルは Dockerfile と呼ばれます (キャメルケースで記述されていないことに注意してください)。

注: 通常のイメージ構築と起動は、プロジェクト全体の CICD の一部である必要があります。これは単なる例です。プロジェクトの CICD には、コマンドの実行やアプリケーションの構築に加えて、コード チェック、感度低下チェック、メッセージ プッシュ公開などの、より複雑な一連のプロセスも含まれています。

まず、React Dockerfile を整理します。

  1. # ノードイメージの使用
  2. ノードから
  3.  
  4. # 作業ディレクトリを準備する
  5. mkdir -p /app/client を実行します。
  6. ワークディレクトリ /app/client
  7.  
  8. # package.json をコピー
  9. package*.json /app/client/ をコピーします。
  10.  
  11. # インストールディレクトリ
  12. npmインストールを実行
  13.  
  14. # ファイルをコピーする
  15. コピー ./app/client/
  16.  
  17. # 開発を有効にする
  18. CMD [ "npm" "run" "start" ]

とても簡単です。コンテナはコンピュータ内のコンピュータとも見なすことができるため、コンピュータ上のファイルを「コンテナ コンピュータ」にコピーすることは非常に必要な手順であることに注意してください。

Express App の Dockerfile は上記のものとほぼ同じです。

  1. # ノードイメージの使用
  2. ノードから
  3.  
  4. # 作業ディレクトリを初期化する
  5. mkdir -p /app/server を実行します。
  6. ワークディレクトリ /app/server
  7.  
  8. # package.json をコピー
  9. package*.json をコピー /app/server/
  10.  
  11. # 依存関係をインストールする
  12. npmインストールを実行
  13.  
  14. # ファイルをコピーする
  15. コピー ./app/server/
  16.  
  17. # 開発を有効にする
  18. CMD [ "npm" "run" "start" ]

次に、prod-docker-compose.yml ファイルを変更します。

  1. バージョン: '3'  
  2. サービス:
  3. クライアント:
  4. 建てる:
  5. コンテキスト: ./client
  6. dockerfile: Dockerファイル
  7. コンテナ名: 'docker-todo-client'  
  8. # 公開ポート
  9. さらす:
  10. - 3000
  11. # 公開ポート
  12. ポート:
  13. - 「3000:3000」  
  14. 依存:
  15. - サーバー
  16. 再起動: 常に
  17. サーバ:
  18. # ビルドディレクトリ
  19. 建てる:
  20. コンテキスト: ./server
  21. dockerfile: Dockerファイル
  22. # コンテナ名
  23. コンテナ名: 'docker-todo-server'  
  24. # 公開ポート
  25. さらす:
  26. - 4200
  27. # ポートマッピング
  28. ポート:
  29. - '4200:4200'  
  30. 再起動: 常に
  31. 依存:
  32. - マリアdb
  33. - レディス
  34. マリアdb:
  35. 画像: mariadb
  36. コンテナ名: 'docker-todo-mariadb'  
  37. 環境:
  38. MARIADB_ROOT_パスワード: '123456'  
  39. MARIADB_DATABASE: 'docker_todo'  
  40. ポート:
  41. - '3306:3306'  
  42. 再起動: 常に
  43. レディス:
  44. 画像: redis
  45. コンテナ名: 'docker-todo-redis'  
  46. ポート:
  47. - '6379:6379'  
  48. 再起動: 常に

上記の構成は理解するのが難しくないはずですが、注意すべき詳細がいくつかあります。

  • ポートを公開してマッピングする必要があります。そうしないと、ポート 3000 と 4200 にローカルでアクセスできません。
  • depends_onの機能は、現在のコンテナを起動する前に、maraidbコンテナとredisコンテナが起動するのを待つことです。

次に、次のコマンドを実行して、ワンクリックで起動します。

  1. docker-compose -f prod-docker-compose.yml アップ -d --build  

次の --build は、実行するたびにイメージをビルドすることを意味します。

しかし、ブーム:

  1. 接続拒否エラー:接続拒否 127.0.0.1:3306
  2. ...

なぜ接続できないのですか?

接続できない問題を解決する

接続できない理由は、ここでは localhost と 127.0.0.1 を使用しているためです。

各コンテナはホストの 127.0.0.1 ネットワーク内にありますが、コンテナは互いの IP アドレスを介して通信し、相互にアクセスする必要があります。公式サイトの紹介によると、コンテナ名を通じて他のコンテナの IP アドレスを取得できるとのことです。

したがって、Express App のホストは 127.0.0.1 ではなく、docker-todo-redis と docker-todo-mariadb である必要があります。以下では、環境変数 NODE_ENV を使用して、アプリが Docker で起動されたかどうかを区別します。

mariadb 接続を変更します。

  1. // データベースに接続する
  2. const sequelize = 新しい Sequelize({
  3. ホスト: process.env.NODE_ENV === 'docker' ? 'docker-todo-mariadb' : "127.0.0.1" ,
  4. データベース: 'docker_todo'
  5. ユーザー名: 'root'
  6. パスワード: '123456'
  7. 方言: 'mariadb'
  8. });

次に、Redis 接続を変更します。

  1. const redis = 新しい Redis({
  2. ポート: 6379、
  3. ホスト: process.env.NODE_ENV === 'docker' ? 'docker-todo-redis' : "127.0.0.1" ,
  4. });

次に、/server/Dockerfile に NODE_ENV=docker を追加します。

  1. # ノードイメージの使用
  2. ノードから
  3.  
  4. # 作業ディレクトリを初期化する
  5. mkdir -p /app/server を実行します。
  6. ワークディレクトリ /app/server
  7.  
  8. # package.json をコピー
  9. package*.json をコピー /app/server/
  10.  
  11. 環境変数 NODE_ENV=docker
  12.  
  13. # 依存関係をインストールする
  14. npmインストールを実行
  15.  
  16. # ファイルをコピーする
  17. コピー ./app/server/
  18.  
  19. # 開発を有効にする
  20. CMD [ "npm" "run" "start" ]

次に、「ワンクリック スタート」コマンドを実行して、本番環境を起動します。

  1. docker-compose -f prod-docker-compose.yml アップ -d --build  

要約する

簡単に言えば、Dockerfile は Docker イメージを構築するために使用され、私たちが普段使用する CICD やパイプラインに多少似ています。 docker-compose の機能は、1 回のクリックで N 個のコンテナを「プルアップ」することです。

上記の例全体は Github で公開されており、クローンして自分で試してみることができます。

<<:  Kubernetes で Apache Spark を実行する方法

>>:  政府クラウドとパブリッククラウドの市場規模は2020年に81.4億人民元に達した

推薦する

serverbound-5 USD/80 GB 保護/15 TB トラフィック/KVM/512 MB メモリ/20 GB SSD

新しいものを紹介します。serverbound.com は、時間単位で支払う VPS ビジネスです。...

ネットホスティング、無制限のウェブサイト構築、仮想ホスティング、月額 3.95 ドルの支払い(独立した IP の方が安い)

ホスティング プロバイダーの nethosting を紹介したいと思います。今日は主に、同社の仮想ホ...

Alibaba Cloud PolarDB はどのようにして 6 倍のパフォーマンス差と 100 TB の容量を実現するのでしょうか?

I. PolarDB 製品アーキテクチャの概要PolarDB は、第 3 世代のクラウド コンピュー...

reprisehosting: シアトルでAlipayに公式接続された超格安サーバーを提供

格安サーバーを販売するアメリカの会社reprisehostingが、正式にAlipay決済を導入した...

SaaS が急速に普及する中、企業はどのようにして「クラウド移行」を実現できるのでしょうか?

近年、クラウドコンピューティングとビッグデータの発展に伴い、クラウドサービスはビジネス革新と企業アッ...

「業界の専門家」がCRICと提携:テクノロジーで工業団地を強化し、工業都市のスマートな発展を促進

「ファーウェイ不動産業界デジタル化白書」は、業界トップ50社を徹底的に調査した上で、「専門家」ファー...

3D ポイントクラウド認識は安全ですか?ミシガン大学は、深刻な歪みに対処するためにデータセットの堅牢な分析を提案している

3D ポイント クラウドは、3D 認識技術で広く使用されています。自動運転や医療画像処理など、一部の...

北朝鮮のサイバー攻撃事件

2014年11月24日、ハッカー集団「Guardians of Peace」がソニー・ピクチャーズの...

分散クラウドが次世代のクラウド コンピューティングである理由は何ですか?ガートナーのアナリストが解説

クラウド コンピューティングは、企業にいくつかの重要なメリットをもたらします。第 1 に、ハードウェ...

SEOマーケターの目にはどちらが人気か:WeChatとWeibo

最近皆さんが書いた記事を読んでいると、WeChatが以前よりも頻繁に言及され、皆さんの注目もより集中...

メタバースはBaidu Socialを救えるか?

今年に入ってから、「メタバース」という概念が世界中で人気を集めており、国内のインターネット大手やベン...

SEO ケース分析: 適切なディレクトリ構造は SEO ランキングに役立ちます

仕事柄、SEO がどのように行われているか、ウェブサイトの重量は安定しているか、収益はどうなっている...

igniteservers - カナダの $3.39/年/32M メモリ/無制限トラフィック/460G 高セキュリティ VPS

朝陽区の人々の反応によると、「このバカは逃げた!」 Igniteservers は今年 8 月に設立...

#11.11# Gouyun: 全品40%オフ、香港 (CN2\CMI\Ali\BGP)、日本 (Softbank\IIJ\BGP)、韓国 (BGP)、ドイツ + オランダ (AS9929)、ロシア (CN2)、米国 (CN2 GIA\AS9929)

毎年恒例のダブルイレブンが到来し、Gouyunも例外ではありません。また、毎年恒例の最低価格イベント...