ゴラン は、開発者がスケーラブルで安全な Web アプリケーションを迅速に開発できるように設計されています。 Goは、使いやすく、安全で、 パフォーマンスの高い Web サーバー 独自のWebテンプレートライブラリと一緒に。 エンタープライズユーザーは、この言語を活用して、迅速なクロスプラットフォーム展開も行います。 その ゴルーチン、ネイティブコンパイル、およびURIベースのパッケージ名前空間により、Goコードは依存関係のない単一の小さなバイナリにコンパイルされるため、非常に高速になります。
開発者はまた、Goのパフォーマンスを支持しています。 同時実行モデル およびCPUのスケーラビリティ。 開発者が内部リクエストを処理する必要があるときはいつでも、Pythonスレッドが行うリソースの10分の1しか消費しない個別のゴルーチンを使用します。 静的リンクを介して、Goは実際にすべての依存関係ライブラリとモジュールをOSとアーキテクチャに基づいて単一のバイナリファイルに結合します。
Go アプリケーションのコンテナー化が重要なのはなぜですか?
Go バイナリは、小さくて自己完結型の実行可能ファイルです。 ただし、アプリケーション コードは、追加のプログラムや Web アプリケーションに適応するため、時間の経過と共に必然的に大きくなります。 これらのアプリには、テンプレート、アセット、データベース構成ファイルが付属している場合があります。 同期が崩れ、依存関係地獄に遭遇し、障害のあるデプロイをプッシュするリスクが高くなります。
コンテナーを使用すると、これらのファイルをバイナリと同期できます。 彼らが また、アプリケーション全体に対して単一のデプロイ可能なユニットを作成するのにも役立ちます。 これには、コード (またはバイナリ)、ランタイム、およびそのシステム ツールまたはライブラリが含まれます。 最終的に 彼らが ローカルでコーディングとテストを行いながら、開発と運用の一貫性を確保できます。
Go アプリケーションのセットアップについて説明し、コンテナー化中の Docker SDK の役割について説明します。
目次
アプリケーションのビルド
このチュートリアルでは、Go を使用して基本的なタスク システム (Gopher) を構築する方法を学習します。
まず、Docker を使用してタスクを実行するシステムを Go で作成します。 次に、アプリケーションの Docker イメージをビルドします。 この例では、 Docker SDK クールなプロジェクトを構築するのに役立ちます。 始めましょう。
主要コンポーネント
始める
始める前に、システムに Goをインストールする 必要があります。 完了したら、次の手順に従って、Docker SDK を使用して基本的なタスク管理システムを構築します。
最後にディレクトリ構造を示します。
➜ tree gopher gopher ├── go.mod ├── go.sum ├── internal │ ├── container-manager │ │ └── container_manager.go │ ├── task-runner │ │ └── runner.go │ └── types │ └── task.go ├── main.go └── task.yaml 4 directories, 7 files
できます ここをクリック をクリックして、この例用に開発された完全なソース コードにアクセスします。 このガイドでは重要なスニペットを活用していますが、完全なコードは全体を通して文書化されていません。
version: v0.0.1 tasks: - name: hello-gopher runner: busybox command: ["echo", "Hello, Gopher!"] cleanup: false - name: gopher-loops runner: busybox command: [ "sh", "-c", "for i in `seq 0 5`; do echo 'gopher is working'; sleep 1; done", ] cleanup: false
タスクの定義
何よりもまず、タスク構造を定義する必要があります。 このタスクは、次の構造を持つ YAML 定義になります。
次の表では、タスク定義について説明します。
タスク定義ができたので、同等の Go 構造体を作成しましょう。
SGoのトラクトは、型付きフィールドのコレクションです。 データをグループ化してレコードを形成する場合に便利です。 例えばこの Task
タスク 構造体型には 、
、、
、 Runner Comman
d および Cleanup Nam e田畑。
// internal/types/task.go package types // TaskDefinition represents a task definition document. type TaskDefinition struct { Version string `yaml:"version,omitempty"` Tasks []Task `yaml:"tasks,omitempty"` } // Task provides a task definition for gopher. type Task struct { Name string `yaml:"name,omitempty"` Runner string `yaml:"runner,omitempty"` Command []string `yaml:"command,omitempty"` Cleanup bool `yaml:"cleanup,omitempty"` }
タスクランナーの作成
次に必要なのは、タスクを実行できるコンポーネントです。 これにはインターフェイスを使用します。 は、メソッド シグネチャの名前付きコレクションです。 この例のタスクランナーでは、weは単にそれを呼びます Runner
以下で定義します。
// internal/task-runner/runner.go type Runner interface { Run(ctx context.Context, doneCh chan<- bool) }
完了チャネル (完了Ch). これは、タスクを非同期で実行するために必要であり、このタスクが完了すると通知されます。
タスクランナーの完全な定義を見つけることができます ここは.ただし、この例では、コードの特定の部分を強調表示することに固執します。
// internal/task-runner/runner.go func NewRunner(def types.TaskDefinition) (Runner, error) { client, err := initDockerClient() if err != nil { return nil, err } return &runner{ def: def, containerManager: cm.NewContainerManager(client), }, nil } func initDockerClient() (cm.DockerClient, error) { cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { return nil, err } return cli, nil }
ザ NewRunner
構造体のインスタンスを返し、 ランナー インターフェイス。 インスタンスは、Docker エンジンへの接続も保持します。 ザ initDockerClient
関数は、環境変数から Docker API クライアント インスタンスを作成することによって、この接続を初期化します。
デフォルトでは、この関数は Unix ソケット経由で HTTP 接続を作成します unix://var/run/docker.sock
(デフォルトの Docker ホスト) をクリックします。 ホストを変更する場合は、 DOCKER_HOST
環境変数。 ザ FromEnv
環境変数を読み取り、それに応じて変更を加えます。
ザ Run
以下に定義する関数は比較的基本的なものです。 タスクのリストをループして実行します。 また、という名前のチャネルも使用します。 taskDoneCh
をクリックして、タスクがいつ完了したかを確認します。 受け取ったかどうかを確認することが重要です 完成です この関数から戻る前に、すべてのタスクからのシグナル。
// internal/task-runner/runner.go func (r *runner) Run(ctx context.Context, doneCh chan<- bool) { taskDoneCh := make(chan bool) for _, task := range r.def.Tasks { go r.run(ctx, task, taskDoneCh) } taskCompleted := 0 for { if <-taskDoneCh { taskCompleted++ } if taskCompleted == len(r.def.Tasks) { doneCh <- true return } } } func (r *runner) run(ctx context.Context, task types.Task, taskDoneCh chan<- bool) { defer func() { taskDoneCh <- true }() fmt.Println("preparing task - ", task.Name) if err := r.containerManager.PullImage(ctx, task.Runner); err != nil { fmt.Println(err) return } id, err := r.containerManager.CreateContainer(ctx, task) if err != nil { fmt.Println(err) return } fmt.Println("starting task - ", task.Name) err = r.containerManager.StartContainer(ctx, id) if err != nil { fmt.Println(err) return } statusSuccess, err := r.containerManager.WaitForContainer(ctx, id) if err != nil { fmt.Println(err) return } if statusSuccess { fmt.Println("completed task - ", task.Name) // cleanup by removing the task container if task.Cleanup { fmt.Println("cleanup task - ", task.Name) err = r.containerManager.RemoveContainer(ctx, id) if err != nil { fmt.Println(err) } } } else { fmt.Println("failed task - ", task.Name) } }
内部 run
機能は、 runner
.タスクを受け入れ、それを Docker コンテナーに変換します。 ある コンテナマネージャー Docker コンテナーの形式でタスクを実行します。
コンテナマネージャー
コンテナマネージャーは、次の責任を負います。
-
タスクの Docker イメージをプルする
-
タスクコンテナの作成
-
タスクコンテナの開始
-
コンテナーの完了を待機しています
-
コンテナの取り外し (必要な場合)
したがって、Goに関しては、以下に示すようにコンテナマネージャーを定義できます。
// internal/container-manager/container_manager.go type ContainerManager interface { PullImage(ctx context.Context, image string) error CreateContainer(ctx context.Context, task types.Task) (string, error) StartContainer(ctx context.Context, id string) error WaitForContainer(ctx context.Context, id string) (bool, error) RemoveContainer(ctx context.Context, id string) error } type DockerClient interface { client.ImageAPIClient client.ContainerAPIClient } type ImagePullStatus struct { Status string `json:"status"` Error string `json:"error"` Progress string `json:"progress"` ProgressDetail struct { Current int `json:"current"` Total int `json:"total"` } `json:"progressDetail"` } type containermanager struct { cli DockerClient }
ザ containerManager
インターフェイス というフィールドがあります cli
と DockerClient
種類。 インターフェイスには、Docker API の 2 つのインターフェイスが埋め込まれます。 ImageAPIClient そして ContainerAPIClient.Wこれらのインターフェースが必要ですか?
のために ContainerManager
インターフェイス 正しく動作するには、Docker エンジンと API のクライアントとして機能する必要があります。 クライアントがイメージとコンテナーを効果的に操作するには、必要な API を提供する型である必要があります。 Docker API のコア インターフェイスを埋め込み、新しいインターフェイスを作成する必要があります。
ザ initDockerClient
関数(上記の runner.go
) は、これらの必要なインターフェイスをシームレスに実装するインスタンスを返します。 ドキュメントを確認する ここは を使用して、Docker クライアントの作成時に返される内容をよりよく理解できます。
その間、あなたは見ることができます コンテナマネージャの完全な定義 ここは.
手記: ここではコンテナマネージャのすべての機能を個別にカバーしていませんが、そうでなければブログが広すぎるでしょう。
エントリポイント
個々のコンポーネントについて説明したので、すべてを組み立てましょう main.go
, これが私たちのエントリポイントです。 パッケージ main
Goコンパイラに、パッケージを共有ライブラリではなく実行可能プログラムとしてコンパイルする必要があることを通知します。 ザ main()
の関数 main
package はプログラムのエントリ ポイントです。
// main.go package main func main() { args := os.Args[1:] if len(args) < 2 || args[0] != argRun { fmt.Println(helpMessage) return } // read the task definition file def, err := readTaskDefinition(args[1]) if err != nil { fmt.Printf(errReadTaskDef, err) } // create a task runner for the task definition ctx := context.Background() runner, err := taskrunner.NewRunner(def) if err != nil { fmt.Printf(errNewRunner, err) } doneCh := make(chan bool) go runner.Run(ctx, doneCh) <-doneCh }
これが何です 私たちのGoプログラムは:
-
引数を検証します。
-
タスク定義を読み取ります
-
タスクランナーを初期化し、次にコンテナマネージャーを初期化します
-
ランナーから最終信号を受信するための完了チャネルを作成します
-
タスクを実行します
タスクシステムの構築
1)リポジトリのクローンを作成する
ソース コードは GitHub でホストされています。 次のコマンドを使用して 、リポジトリをローカルマシンにクローンします。
git clone https://github.com/dockersamples/gopher-task-system.git
2) Bタスクシステムの構築
ザ ビルドする
命令 パッケージとその依存関係をコンパイルします。
go build -o gopher
3)タスクを実行する
gopherファイルを直接実行して、次のようにタスクを実行できます。
$ ./gopher run task.yaml preparing task - gopher-loops preparing task - hello-gopher starting task - gopher-loops starting task - hello-gopher completed task - hello-gopher completed task - gopher-loops
4)すべてのタスクコンテナを表示する
コンテナーの完全な一覧は、 Docker デスクトップ内で表示できます。 ダッシュボード には、次の情報が明確に表示されます。
5)CLI経由ですべてのタスクコンテナを表示する
または、 docker ps -a
また、すべてのタスクコンテナを表示することもできます。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 396e25d3cea8 busybox "sh -c 'for i in `se…" 6 minutes ago Exited (0) 6 minutes ago gopher-loops aba428b48a0c busybox "echo 'Hello, Gopher…" 6 minutes ago Exited (0) 6 minutes ago
なお、 task.yaml
ザ cleanup
フラグはに設定されています false
両方のタスクに対して。 これは、タスクの完了後にコンテナー リストを取得するために意図的に行いました。 これを true
タスクコンテナを自動的に削除します。
シーケンス図
結論
Docker は、個々のコンテナーを構築、共有、および実行するためのソフトウェア開発ツールのコレクションです。 Docker SDK を使用すると、Docker ベースのアプリとソリューションをすばやく簡単に構築してスケーリングできます。 また、Dockerが内部でどのように機能するかをよりよく理解できます。 このような例をさらに共有し、Docker SDKで取り組むことができる他のプロジェクトをすぐに紹介することを楽しみにしています。
Docker SDK の活用をご自身で始めてみませんか? インストール手順、クイックスタートガイド、ライブラリ情報については、 ドキュメント を参照してください。