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億人民元に達した

推薦する

2014年インターネット金融セキュリティレポート

2015 年 4 月 30 日、Green Alliance Technology は 2014 年...

チャンネルAPPプロモーション運用詳細

概要: Android チャネル操作では何に注意すべきでしょうか? 1. チャンネルのゲームプレイと...

クラウド コンピューティングのパワーを解き放つ: Kubernetes の詳細なガイド

1. Kubernetesとは Kubernetes は、大規模なコンテナ化されたアプリケーションの...

モバイル検索キーワードマーケティングは詐欺だと非難され、中小企業経営者は騙されたと感じている

検索キーワードを購入し、Baidu(Weibo)のプロモーションプラットフォームを活用することで、多...

人工知能は止められない。 Advantech WISE-PaaS 3.0がイノベーションを推進

アドバンテックは、2018年11月1日~2日に開催されたアドバンテックIoT共創サミットにおいて、プ...

コンテンツこそが王様です。ウェブサイトのコンテンツ戦略をどのように策定すればよいでしょうか?

場合によっては、Web サイトにリンク可能なコンテンツが不足していることがあります。これを解決するに...

cmivps: 香港サーバー、無制限のトラフィック、超高構成、複数の IPv4、月額 169 ドルから、CN2+PCCW 回線

cmivps は香港データセンターに独立したサーバーを追加しました。これらの香港サーバーは、2*e5...

Sangfor は、新世代のクラウドネイティブ ワークロードでアプリケーションの公開と負荷分散の課題を解決します。

6月9日から10日まで、「金融電子化」誌が主催し、福建省農村信用協同組合連合会と福建海峡銀行が共催す...

変曲点?オラクルはより多くの顧客を獲得する必要があるかもしれない

オラクルの第4四半期決算報告によると、同社の業績は前年同期比でわずかに遅れをとったものの、非GAAP...

SEOはスキルを追求する必要はなく、常識から始めましょう

今では SEO を学ぶことは 4 年前ほど難しくありません。当時、SEO トレーニングに参加したとき...

米国(ロサンゼルス)の無制限 VPS:desivps、最低 $18.99/年、1Gbps 帯域幅、KVM+SSD RAID10

desivps は現在、米国ロサンゼルスのデータセンターで、無制限のトラフィック、1Gbps の帯域...

3.5年間のオンライン採用経験のまとめ:データに基づいた思考

現在のオンライン募集の普及は、実は私たちがこの業界に入った当初は想像もしていなかったことです。という...

ファイバーステートはどうですか?ソルトレイクシティデータセンター専用サーバーの詳細レビュー

Fiberstateは新しいビジネスです。主な業務は、ソルトレイクシティのコンピュータールームでのサ...

デスクトップ検索が新時代の要素に受け入れられにくい理由

デスクトップ PC の絶対的な中核ビジネスとして、検索は常にインターネット企業やウェブマスターによる...