Ken的杂谈
  • Ken的杂谈 (current)
  • 关于
  • 杂谈
    Java Spring Spring Boot Spring Cloud MyBatis C# .NET Core .NET ASP.NET Core ASP.NET ClassLibrary Mono 数据库 MySQL SQL Server 网络 缓存 Web Linux CentOS Ubuntu macOS Windows openEuler Nginx ServiceStack JS/JQ 正则 工具 IDE Grafana Exceptions CI/CD Solution 微服务 Arch Docker 杂谈
  • 系列
    Java 快速入门系列教程 Spring Boot 入门教程 Spring Boot 2.x 入门教程 Spring Cloud 入门教程 .NET Core 快速入门教程 ASP.NET Core 2.1 入门教程 CentOS 7 快速上手教程 Ubuntu快速上手入门教程 Hyper-V基础教程 Docker入门教程
  • GitHub

Docker入门:使用Dockerfile构建Docker镜像

Linux Docker @ 2022-12-10 16:04:04 · 阅读:(13471)

一、前言

我们通过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
image.png
也可以试试访问http://localhost:8000/ken,将会看到不一样的内容

三、推送镜像到官方仓库

1、注册Docker账号

访问 https://hub.docker.com/signup ,注册自己的Docker账号

截图中的邮箱仅为示例,实际并不存在

image.png

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页看到推送的镜像
image.png
也可以直接访问 https://hub.docker.com/r/kentalk/helloworld/tags,查看Repository下的所有Tag
image.png
这里可以通过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 将会看到:
image.png

四、备注

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入门:使用数据卷、文件挂载进行数据存储与共享

Ken的杂谈

本文由 ken.io 创作,采用CC BY 3.0 CN协议 进行许可。 可自由转载、引用、甚至修改,但需署名作者且注明出处。

Linux Docker

随笔目录


    © Copyright 2012-2025 Ken的杂谈

    豫ICP备10025012号

    ASP.NET Core(6.0) on Linux