使用 Docker 引擎 SDK 和 Docker API 的範例
在您安裝 Docker之後,您可以安裝 Go 或 Python SDK,也可以試用 Docker 引擎 API。
每個範例都示範如何使用 Go 和 Python SDK 以及使用 curl
的 HTTP API 執行指定的 Docker 操作。
執行容器
第一個範例示範如何使用 Docker API 執行容器。在命令列上,您會使用 docker run
命令,但從您自己的應用程式執行也很容易。
這相當於在命令提示字元中輸入 docker run alpine echo hello world
package main
import (
"context"
"io"
"os"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
reader, err := cli.ImagePull(ctx, "docker.io/library/alpine", image.PullOptions{})
if err != nil {
panic(err)
}
defer reader.Close()
// cli.ImagePull is asynchronous.
// The reader needs to be read completely for the pull operation to complete.
// If stdout is not required, consider using io.Discard instead of os.Stdout.
io.Copy(os.Stdout, reader)
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: "alpine",
Cmd: []string{"echo", "hello world"},
Tty: false,
}, nil, nil, nil, "")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
panic(err)
}
statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
select {
case err := <-errCh:
if err != nil {
panic(err)
}
case <-statusCh:
}
out, err := cli.ContainerLogs(ctx, resp.ID, container.LogsOptions{ShowStdout: true})
if err != nil {
panic(err)
}
stdcopy.StdCopy(os.Stdout, os.Stderr, out)
}
import docker
client = docker.from_env()
print(client.containers.run("alpine", ["echo", "hello", "world"]))
$ curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
-d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}' \
-X POST http://localhost/v1.47/containers/create
{"Id":"1c6594faf5","Warnings":null}
$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v1.47/containers/1c6594faf5/start
$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v1.47/containers/1c6594faf5/wait
{"StatusCode":0}
$ curl --unix-socket /var/run/docker.sock "http://localhost/v1.47/containers/1c6594faf5/logs?stdout=1"
hello world
當使用 cURL 透過 Unix 通訊端連線時,主機名稱並不重要。先前的範例使用 localhost
,但任何主機名稱都可以使用。
重要
前面的範例假設您使用的是 cURL 7.50.0 或更高版本。較舊版本的 cURL 在使用通訊端連線時,會使用非標準的 URL 表示法。
如果您使用的是較舊版本的 cURL,請改用
http:/<API 版本>/
,例如:http:/v1.47/containers/1c6594faf5/start
。
在背景執行容器
您也可以在背景執行容器,相當於輸入 docker run -d bfirsh/reticulate-splines
package main
import (
"context"
"fmt"
"io"
"os"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
imageName := "bfirsh/reticulate-splines"
out, err := cli.ImagePull(ctx, imageName, image.PullOptions{})
if err != nil {
panic(err)
}
defer out.Close()
io.Copy(os.Stdout, out)
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: imageName,
}, nil, nil, nil, "")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
panic(err)
}
fmt.Println(resp.ID)
}
import docker
client = docker.from_env()
container = client.containers.run("bfirsh/reticulate-splines", detach=True)
print(container.id)
$ curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
-d '{"Image": "bfirsh/reticulate-splines"}' \
-X POST http://localhost/v1.47/containers/create
{"Id":"1c6594faf5","Warnings":null}
$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v1.47/containers/1c6594faf5/start
列出和管理容器
您可以使用 API 列出正在執行的容器,就像使用 docker ps
一樣
package main
import (
"context"
"fmt"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
containers, err := cli.ContainerList(ctx, containertypes.ListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Println(container.ID)
}
}
import docker
client = docker.from_env()
for container in client.containers.list():
print(container.id)
$ curl --unix-socket /var/run/docker.sock http://localhost/v1.47/containers/json
[{
"Id":"ae63e8b89a26f01f6b4b2c9a7817c31a1b6196acf560f66586fbc8809ffcd772",
"Names":["/tender_wing"],
"Image":"bfirsh/reticulate-splines",
...
}]
停止所有正在執行的容器
現在您知道有哪些容器存在,您可以對它們執行操作。這個範例會停止所有正在執行的容器。
注意事項
請勿在正式伺服器上執行此操作。此外,如果您使用的是 Swarm 服務,容器會停止,但 Docker 會建立新的容器來保持服務以其設定的狀態執行。
package main
import (
"context"
"fmt"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
containers, err := cli.ContainerList(ctx, containertypes.ListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Print("Stopping container ", container.ID[:10], "... ")
noWaitTimeout := 0 // to not wait for the container to exit gracefully
if err := cli.ContainerStop(ctx, container.ID, containertypes.StopOptions{Timeout: &noWaitTimeout}); err != nil {
panic(err)
}
fmt.Println("Success")
}
}
import docker
client = docker.from_env()
for container in client.containers.list():
container.stop()
$ curl --unix-socket /var/run/docker.sock http://localhost/v1.47/containers/json
[{
"Id":"ae63e8b89a26f01f6b4b2c9a7817c31a1b6196acf560f66586fbc8809ffcd772",
"Names":["/tender_wing"],
"Image":"bfirsh/reticulate-splines",
...
}]
$ curl --unix-socket /var/run/docker.sock \
-X POST http://localhost/v1.47/containers/ae63e8b89a26/stop
列印特定容器的日誌
您也可以對個別容器執行操作。這個範例會印出指定 ID 容器的日誌。您需要在執行程式碼之前修改它,將容器的硬編碼 ID 更改為要印出日誌的容器 ID。
package main
import (
"context"
"io"
"os"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
options := container.LogsOptions{ShowStdout: true}
// Replace this ID with a container that really exists
out, err := cli.ContainerLogs(ctx, "f1064a8a4c82", options)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, out)
}
import docker
client = docker.from_env()
container = client.containers.get('f1064a8a4c82')
print(container.logs())
$ curl --unix-socket /var/run/docker.sock "http://localhost/v1.47/containers/ca5f55cdb/logs?stdout=1"
Reticulating spline 1...
Reticulating spline 2...
Reticulating spline 3...
Reticulating spline 4...
Reticulating spline 5...
列出所有映像檔
列出引擎上的映像檔,類似於 docker image ls
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
images, err := cli.ImageList(ctx, image.ListOptions{})
if err != nil {
panic(err)
}
for _, image := range images {
fmt.Println(image.ID)
}
}
import docker
client = docker.from_env()
for image in client.images.list():
print(image.id)
$ curl --unix-socket /var/run/docker.sock http://localhost/v1.47/images/json
[{
"Id":"sha256:31d9a31e1dd803470c5a151b8919ef1988ac3efd44281ac59d43ad623f275dcd",
"ParentId":"sha256:ee4603260daafe1a8c2f3b78fd760922918ab2441cbb2853ed5c439e59c52f96",
...
}]
拉取映像檔
提取映像檔,例如 docker pull
package main
import (
"context"
"io"
"os"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
out, err := cli.ImagePull(ctx, "alpine", image.PullOptions{})
if err != nil {
panic(err)
}
defer out.Close()
io.Copy(os.Stdout, out)
}
import docker
client = docker.from_env()
image = client.images.pull("alpine")
print(image.id)
$ curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.47/images/create?fromImage=alpine"
{"status":"Pulling from library/alpine","id":"3.1"}
{"status":"Pulling fs layer","progressDetail":{},"id":"8f13703509f7"}
{"status":"Downloading","progressDetail":{"current":32768,"total":2244027},"progress":"[\u003e ] 32.77 kB/2.244 MB","id":"8f13703509f7"}
...
使用驗證拉取映像檔
使用身份驗證提取映像檔,例如 docker pull
注意事項
憑證以明碼傳送。Docker 的官方 registry 使用 HTTPS。私人 registry 也應該設定為使用 HTTPS。
package main
import (
"context"
"encoding/base64"
"encoding/json"
"io"
"os"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
authConfig := registry.AuthConfig{
Username: "username",
Password: "password",
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
panic(err)
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
out, err := cli.ImagePull(ctx, "alpine", image.PullOptions{RegistryAuth: authStr})
if err != nil {
panic(err)
}
defer out.Close()
io.Copy(os.Stdout, out)
}
Python SDK 會從憑證存放區檔案中擷取身份驗證資訊,並與憑證輔助程式整合。可以覆寫這些憑證,但这超出了本指南的範圍。使用 docker login
後,Python SDK 會自動使用這些憑證。
import docker
client = docker.from_env()
image = client.images.pull("alpine")
print(image.id)
這個範例會將憑證保留在您的 shell 歷史記錄中,因此請將其視為一個簡單的實作。憑證會以 Base-64 編碼的 JSON 結構傳遞。
$ JSON=$(echo '{"username": "string", "password": "string", "serveraddress": "string"}' | base64)
$ curl --unix-socket /var/run/docker.sock \
-H "Content-Type: application/tar"
-X POST "http://localhost/v1.47/images/create?fromImage=alpine"
-H "X-Registry-Auth"
-d "$JSON"
{"status":"Pulling from library/alpine","id":"3.1"}
{"status":"Pulling fs layer","progressDetail":{},"id":"8f13703509f7"}
{"status":"Downloading","progressDetail":{"current":32768,"total":2244027},"progress":"[\u003e ] 32.77 kB/2.244 MB","id":"8f13703509f7"}
...
提交容器
提交容器以從其內容建立映像檔
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer cli.Close()
createResp, err := cli.ContainerCreate(ctx, &container.Config{
Image: "alpine",
Cmd: []string{"touch", "/helloworld"},
}, nil, nil, nil, "")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx, createResp.ID, container.StartOptions{}); err != nil {
panic(err)
}
statusCh, errCh := cli.ContainerWait(ctx, createResp.ID, container.WaitConditionNotRunning)
select {
case err := <-errCh:
if err != nil {
panic(err)
}
case <-statusCh:
}
commitResp, err := cli.ContainerCommit(ctx, createResp.ID, container.CommitOptions{Reference: "helloworld"})
if err != nil {
panic(err)
}
fmt.Println(commitResp.ID)
}
import docker
client = docker.from_env()
container = client.containers.run("alpine", ["touch", "/helloworld"], detach=True)
container.wait()
image = container.commit("helloworld")
print(image.id)
$ docker run -d alpine touch /helloworld
0888269a9d584f0fa8fc96b3c0d8d57969ceea3a64acf47cd34eebb4744dbc52
$ curl --unix-socket /var/run/docker.sock\
-X POST "http://localhost/v1.47/commit?container=0888269a9d&repo=helloworld"
{"Id":"sha256:6c86a5cd4b87f2771648ce619e319f3e508394b5bfc2cdbd2d60f59d52acda6c"}