一、前言
我们通过Docker build命令以及Dockerfile把我们的应用以及应用依赖的资源及环境打包成Docker镜像,帮助我们在各种我们需要的环境中部署应用,让我们不再担心环境差异带来的应用部署问题
1、本篇主要内容
- Docker build命令介绍
- Dockerfile文件及常用参数介绍
- Docker build+Dockerfile制作Docker镜像
- Docker镜像发布到公共仓库
2、环境信息
环境 | 说明 |
---|---|
Docker | Docker CE 20.10.21 |
Docker Desktop | 4.14 |
Docker Golang镜像 | 1.19.4 |
Golang | 1.19.4 |
Windows | Windows 11 |
二、镜像制作
创建镜像制作根目录,例如:d:\docker\helloworld(Windows),~/docker/helloworld(macOS),后续所有文件都放在该目录中
1、准备应用代码
用golang写的一个简单http server,监听8000端口,默认输出helloworld,新建helloworld.go保存以下代码
package main
import (
"fmt"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
log.Println("received request from", r.RemoteAddr, r.URL.Path[1:])
var welcome = r.URL.Path[1:]
if len(welcome) == 0 {
welcome = "World"
}
fmt.Fprintf(w, "Hello, %s! ---ken.io", welcome)
}
func main() {
http.HandleFunc("/", handler)
log.Println("starting server on port 8000")
log.Fatal(http.ListenAndServe(":8000", nil))
}
2、编写Dockerfile文件
Dockerfile 是用于Docker镜像的文本文件(无后缀名),包含所有我们需要用于创建Docker镜像的命令,例如:指定基础镜像、安装依赖的软件、配置环境变量、添加文件和目录、定义容器启动时运行的命令等
# 使用官方提供的 Go 镜像作为基础镜像
FROM golang:1.19.4
# 将工作目录设置为 /app
WORKDIR /app
# 将当前目录下的所有内容复制到 /app 下
COPY . /app
# 允许宿主机访问容器的 8000 端口
EXPOSE 8000
# 设置容器进程为:go run helloworld.go
CMD go run helloworld.go
3、编译镜像文件
#进入目录
d: && cd d:\docker\helloworld
#编译镜像(默认为latest)(注意结尾一定要加.)
docker build -t helloworld .
#编译指定版本镜像(注意结尾一定要加.)
docker build -t helloworld:1.0 .
#查看本地镜像
docker images
#镜像列表
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld 1.0 c56b0d613f1a 1 minutes ago 992MB
helloworld latest c56b0d613f1a 1 minutes ago 992MB
注意看这里的IMAGE ID是一样的,我们虽然执行了两次Docker build,但是Dockerfile并无变化,Docker很机智的把后创建的Repository Tag指向了同一个Source Image,不信你可以看一下两次docker build命令的输出结果,writing image的sha256值是一模一样的
4、创建并启动容器
#创建并启动容器(默认使用latest版本)
docker run -d --name myhello -p 8000:8000 helloworld
#查看已启动的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1438022c3ae4 helloworld "/bin/sh -c 'go run …" 6 seconds ago Up 5 seconds 0.0.0.0:8000->8000/tcp myhello
看到helloworld的容器且状态为UP,说明容器已正常启动,此时访问 http://localhost:8000/ 将会看到HelloWorld
也可以试试访问http://localhost:8000/ken,将会看到不一样的内容
三、推送镜像到官方仓库
1、注册Docker账号
访问 https://hub.docker.com/signup ,注册自己的Docker账号
截图中的邮箱仅为示例,实际并不存在
2、登录Docker账号
在Docker Client或者Docker Desktop中登录自己的账号,这里使用Docker Client做演示
#登录命令
docker login
#根据命令号交互输入注册时的账号密码即可成功登录
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: kentalk
Password:
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/
3、推送镜像
基于已有本地Docker镜像创建符合Docker规范的Repository: {username}/{repository}
docker tag helloworld kentalk/helloworld
docker tag helloworld:1.0 kentalk/helloworld:1.0
命令执行后再查看下本地镜像
#查看本地镜像
docker images
#镜像列表
REPOSITORY TAG IMAGE ID CREATED SIZE
kentalk/helloworld 1.0 c56b0d613f1a About an hour ago 992MB
kentalk/helloworld latest c56b0d613f1a About an hour ago 992MB
helloworld 1.0 c56b0d613f1a About an hour ago 992MB
helloworld latest c56b0d613f1a About an hour ago 992MB
这里注意IMAGE ID并无变化,新的Repository只是基于本地镜像的引用
推送镜像到docker hub
#执行命令
docker push kentalk/helloworld
#输出示例
Using default tag: latest
The push refers to repository [docker.io/kentalk/helloworld]
c5aba32dc2d8: Pushed
7bc6949046cf: Pushed
3b5b867f93c1: Mounted from library/golang
caf157c05987: Mounted from library/golang
6424bc9210da: Mounted from library/golang
b77487480ddb: Mounted from library/golang
cd247c0fb37b: Mounted from library/golang
cfdd5c3bd77e: Mounted from library/golang
870a241bfebd: Mounted from library/golang
latest: digest: sha256:3fc3bd029a7dd0……caf7fe1601eb27424 size: 2209
虽然我们本地镜像有992MB,但是推送只消耗了2209字节,这是因为我们是基于官方镜像的加工,只需要把Dockerfile上传即可,并不需要把我们本地的镜像文件完整的上传
推送完成后,可以在跟人账号https://hub.docker.com/u/kentalk页看到推送的镜像
也可以直接访问 https://hub.docker.com/r/kentalk/helloworld/tags,查看Repository下的所有Tag
这里可以通过Manage Repository修改镜像介绍等,也可以在Overview查看镜像介绍等信息,这里就不再赘述
4、获取远端镜像
删除本地kentalk开头镜像
docker image rm kentalk/helloworld:latest
docker image rm kentalk/helloworld:1.0
停用并删除已有helloworld容器
docker stop myhello
docker rm myhello
从远端拉取镜像并启动kentalk/helloworld容器
#执行命令
docker run -d --name myhello -p 8000:8000 kentalk/helloworld
#输出内容
Unable to find image 'kentalk/helloworld:latest' locally
latest: Pulling from kentalk/helloworld
Digest: sha256:3fc3bd029a7dd0011ff97c4e2c108296701342c0452886fcaf7fe1601eb27424
Status: Downloaded newer image for kentalk/helloworld:latest
8b7da7d0cc249d00b46739b83d597d27b9c665307a74e42fde8ac5fe67b7edf4
查看镜像运行情况
#查看所有容器
docker ps -a
#容器List
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8b7da7d0cc24 kentalk/helloworld "/bin/sh -c 'go run …" About a minute ago Up About a minute 0.0.0.0:8000->8000/tcp myhello
访问 http://localhost:8000/ken 将会看到:
四、备注
1、Docker build常用参数
参数 | 说明 |
---|---|
-t | 指定Repository以及Tag,例如helloworld:1.0 |
-f | 指定Dockerfile路径,Dockerfile不在当前目录时使用 |
—no-cache | 常见镜像的过程中不使用Build Cache构建镜像 |
—pull | 构建镜像时总是拉取Base Image的最新版本 |
2、Dockerfile常用指令
指令 | 描述 |
---|---|
FROM | 指定基础镜像,可以指定多个,指定多个基础镜像时,编译时也会生成对应的多个镜像 |
MAINTAINER | 指定镜像维护人信息,制作人根据自己情况指定 |
WORKDIR | 设置工作目录,后续的RUN、COPY、CMD等命令都将在工作目录下运行 |
RUN | 构建镜像时运行命令,可以用他安装软件等等 |
COPY | 拷贝文件或目录到镜像中 |
ADD | 拷贝文件或目录到镜像中,如果源文件是gizp等压缩文件,会被自动解压到目标目录 |
ENV | 设置环境变量 |
USER | 为RUN、CMD 和 ENTRYPOINT 执行命令指定运行用户 |
ARG | 由外部启动时必须传入的参数,在容器启动时用–build-arg传递参数 |
EXPOSE | 声明容器暴露给宿主机的端口,可以是一个或者多个以空格间隔 |
HEALTHCHECK | 容器中服务健康检查 |
VOLUME | 用于指定持久化目录 |
CMD | 运行容器时执行,启动的进程会作为容器的主进程,如果有多个CMD指令,如果指定了多个,最后一个生效,这种机制保障了我们基于Base Image制作镜像时可以运行自己想要的程序作为容器主进程 |
ENTRYPOINT | 运行容器时执行,如果有多个 ENTRYPOINT 命令,作用相当于CMD,可以执行比CMD更复杂的命令,如果指定了多个,只有最后一个生效 |
3、本文参考
- https://docs.docker.com/get-started/02_our_app/
- https://docs.docker.com/engine/reference/builder/
- https://yeasy.gitbook.io/docker_practice/image/dockerfile
- 系列名称:Docker入门教程
- 上一篇:Docker入门:Docker安装与基本使用
- 下一篇:Docker入门:使用数据卷、文件挂载进行数据存储与共享