nerdctl Application Practice Manual 【nerdctl 应用实践手册】

1. 实现目标

  • 实现一个go 开发 demo web,并实现构建镜像,运行容器,推送镜像入库。

2. 开发应用

开发环境:linux 、windows、mac

package main

import (
	"fmt"
	"html"
	"log"
	"net/http"
)

func main() {

	fmt.Println("launching server at port 9090")

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		fmt.Fprintf(w, "hello, %q", html.EscapeString(r.URL.Path))
	})

	log.Fatal(http.ListenAndServe(":9090", nil))

}

第一个终端执行:

$ go run main.go 
launching server at port 9090

第二个终端模拟客户端访问,效果如下:

$ curl http://localhost:9090/docker-go
hello, "/docker-go"

$ curl http://localhost:9090/google
hello, "/google"

$ curl http://localhost:9090/google/demo1
hello, "/google/demo1"

3. 编写 Dockerfile

将 上面开发的demo 应用构建一个镜像。

首先,编写一个Dockerfile

FROM golang:latest

RUN mkdir /app

WORKDIR /app

ADD . /app

RUN go build -o main ./server.go

EXPOSE 9090

CMD /app/main

Dockerfile命令作用:

  • FROM golang:latest 以golang的最新的镜像为基础镜像创建
  • RUN mkdir /app 在容器中创建一个app文件夹
  • WORKDIR /app 将这个app认为默认工作文件夹
  • ADD . /app 将当前目录的下的所有文件加入到这个app工作文件夹中
  • RUN go build -o main ./server.go 开始build server.go名称任意 (是你的go项目的程序入口)
  • EXPOSE 9090 向外面暴露9090端口
  • CMD /app/main 然后运行我们build的生成的可执行文件main.exe

4. 构建镜像

$ sudo nerdctl build . -t demo1:v1 
[+] Building 24.3s (10/10) FINISHED                                                                                                                                                     
 => [internal] load build definition from Dockerfile                                                                                                                               0.0s
 => => transferring dockerfile: 158B                                                                                                                                               0.0s
 => [internal] load metadata for docker.io/library/golang:latest                                                                                                                   0.9s
 => [internal] load .dockerignore                                                                                                                                                  0.0s
 => => transferring context: 2B                                                                                                                                                    0.0s
 => [internal] load build context                                                                                                                                                  0.0s
 => => transferring context: 108B                                                                                                                                                  0.0s
 => [1/5] FROM docker.io/library/golang:latest@sha256:2ff79bcdaff74368a9fdcb06f6599e54a71caf520fd2357a55feddd504bcaffb                                                             0.0s
 => => resolve docker.io/library/golang:latest@sha256:2ff79bcdaff74368a9fdcb06f6599e54a71caf520fd2357a55feddd504bcaffb                                                             0.0s
 => CACHED [2/5] RUN mkdir /app                                                                                                                                                    0.0s
 => CACHED [3/5] WORKDIR /app                                                                                                                                                      0.0s
 => CACHED [4/5] ADD . /app                                                                                                                                                        0.0s
 => CACHED [5/5] RUN go build -o main ./main.go                                                                                                                                    0.0s
 => exporting to docker image format                                                                                                                                              22.8s
 => => exporting layers                                                                                                                                                            0.0s
 => => exporting manifest sha256:88bd9d93ab4c3a1f0a0dedb3041548a363e1adf6bf5c8beef7a21af7ba58347a                                                                                  0.0s
 => => exporting config sha256:7523e47d0e4def8ba54b5df919588598e7821192380968df21a6789d4f43ad6b                                                                                    0.0s
 => => sending tarball                                                                                                                                                            22.7s
unpacking docker.io/library/demo1:v1 (sha256:88bd9d93ab4c3a1f0a0dedb3041548a363e1adf6bf5c8beef7a21af7ba58347a)...
Loaded image: docker.io/library/demo1:v1

当然,对于构建镜像来说,我们仍然可以使用 docker 构建镜像。

sudo docker build . -t demo1:v1 

5. 测试应用

创建容器

$ sudo nerdctl run -t -d -p 9090:9090 --name demo demo1:v1
f16ee68da8542b8cf8d30ea2c1c91ad88170361089aa694f6a76e4610d20c37c
  • -d 表示后台运行
  • -p 表示端口映射 将本地的9090端口映射到容器的9090端口
  • demo 新建的容器的名称
  • demo1:v1 容器所使用的镜像的名称

查看容器

$ sudo nerdctl ps
CONTAINER ID    IMAGE                             COMMAND                   CREATED           STATUS    PORTS                     NAMES
f16ee68da854    docker.io/library/demo1:v1        "/bin/sh -c /app/main"    24 seconds ago    Up        0.0.0.0:9090->9090/tcp    demo

测试

$ curl http://localhost:9090/demo
hello, "/demo"

当然,如果9090端口被占用。可以映射其他端口。例如9091:

sudo nerdctl run -t -d -p 9091:9090 --name demo demo1:v1¬

6. 场景运用

在实际开发应用,我们可能希望将配置文件或者数据目录挂载出来,这样,方便更新配置文件,或者存储大量的数据内容。

比如在/root/demo1目录。包含配置文件config.yaml 和目录data,可以通过 -v 命令参数实现挂载。

$ ls /root/demo1/
config.yaml  data
$ sudo nerdctl run -t -d -p 9091:9090 -v /root/demo1/config.yaml:/app/config.yaml -v /root/demo1/data:/app/data  ---name demo demo1:v1

另外,应用也许通过环境变量传递一些变量,例如,用户名、 其他应用访问的域名等等。可以通过 -e 命令参数实现。

$ sudo nerdctl run -t -d -p 9091:9090 -e USER=demo  -v /root/demo1/config.yaml:/app/config.yaml -v /root/demo1/data:/app/data   ---name demo demo1:v1

7. 镜像入库

当我们研发测试通过验证后,需要把镜像推送的镜像仓库,为生产应用提供拉取镜像的新版本。

首先,我们需要在测试环境镜像打包。

$ sudo nerdctl save -o demo1.tar.gz demo1:v1
$ ls demo1.tar.gz  -l
-rw-r--r-- 1 root root 316571136 Dec 19 17:46 demo1.tar.gz

然后,镜像软件包拷贝到适用于推送镜像入库的节点,建议该节点不是仓库节点或者生产的集群,因为,软件包和解压的介质积累过多会导致占用额外的空间,给生产环境带来磁盘爆满的风险。

镜像入库节点的镜像入库工具,同样有多种选择,docker、nerdctl、podman、ctr、crictl等。这里nerdctl 为主。

$ sudo nerdctl load -i demo1.tar.gz
unpacking docker.io/library/demo1:v1 (sha256:88bd9d93ab4c3a1f0a0dedb3041548a363e1adf6bf5c8beef7a21af7ba58347a)...
Loaded image: demo1:v1

registry.ghostwritten.com 仓库名为例。我们希望把镜像demo1:v1推送到 registry.ghostwritten.com 仓库的gpu项目下,注意,如果我们的镜像仓库是harbor部署的,那么项目名需要界面创建好,保障一存在。

首先,给镜像打一个标签。

sudo nerdctl tag demo1:v1 registry.ghostwritten.com/gpu/demo1:v1 

然后推送入库

sudo nerdctl push registry.ghostwritten.com/gpu/demo1:v1 

参考: