1. 什么是Docker
一条小鲸鱼上面有些集装箱,比较形象的说明了 Docker 的特点,以后见到这个图标等同见到了 Docker
2. 容器技术
- Docker 是一个开源的应用容器引擎,它基于Go语音开发,并遵从Apache2.0开源协议
- 使用 Docker 可以让开发者封装他们的应用以及依赖包到一个可移植的容器中,然后发布到任意
- Linux机器上,也可以实现虚拟化
- Docker 容器完全使用沙箱机制,相互之间不会有任何接口,这保证了容器之间的安全性
- Docker 诞生于 2013 年初,目前有两个版本: Community Edition(CE ,社区版 ) 和 EnterpriseEdition(EE,企业版 )
3. 容器与虚拟机区别
- 虚拟机是在一台物理机上,利用虚拟化技术,虚拟出来多个操作系统,每个操作系统之间是隔离的。
- Docker 是开源的应用容器引擎,依然需要先在电脑上安装操作系统,然后安装 Docker 容器管理器。
4. Docker特点
- 更高效的利用系统资源:Docker 对系统资源的利用率很高,无论是应用执行速度,内存损耗或者文件存储速度,都要比传统虚拟 机技术更高效。
- 更快速的启动时间:传统的虚拟化技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级,甚至毫秒级的启动时间,大大节约了开发测试,部署的时间。
- 一致的运行环境:Docker 是一个采用集装箱思想出现技术,把相关依赖及运行代码打到一起,达到开发环境,测试环境,部署环境一样,减少由于环境不一致而出现问题
- 持续支付和部署:对开发和运维人员来说,最希望就是一次创建和部署,可以在任意地方运行。
- 更轻松的迁移:Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本、其运行结果是一致的。
- 更轻松的维护和扩展:Docker 使用的分层存储以及镜像技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得十分简单。
5. Docker客户端和服务器
- Docker 是一个客户端 – 服务器( C/S )架构程序。
- Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。
- Docker 提供了一个命令行工具 Docker 以及一整套 RESTful API 。
- 你可以在同一台宿主机上运行 Docker 守护进程和客户端,也可以从本地的 Docker 客户端连接到运 行在另一台宿主机上的远程 Docker 守护进程。
6. Docker镜像
- 镜像是构建 Docker 的基石。
- 用户基于镜像来运行自己的容器。
- 镜像也是 Docker 生命周期中的 “ 构建 ” 部分。
- 镜像是基于联合文件系统的一种层式结构,由一系列指令一步一步构建出来。
- 例如:添加一个文件;执行一个命令;打开一个窗口。也可以将镜像当作容器的 “ 源代码 ” 。
- 镜像体积很小,非常 “ 便携 ” ,易于分享、存储和更新。
7. Registry(注册中心/镜像仓库)
- Docker 用 Registry 来保存用户构建的镜像。
- Registry 分为公共和私有两种。
- Docker 公司运营公共的 Registry 叫做 Docker Hub 。
- 用户可以在 Docker Hub 注册账号,分享并保存自己的镜像
- 说明:在 Docker Hub 下载镜像巨慢,可以自己构建私有的 Registry
8. Docker容器
- Docker 可以帮助你构建和部署容器,你只需要把自己的应用程序或者服务打包放进容器即可。
- 容器是基于镜像启动起来的,容器中可以运行一个或多个进程。
- 我们可以认为,镜像是 Docker 生命周期中的构建或者打包阶段,而容器则是启动或者执行阶段。
- 容器基于镜像启动,一旦容器启动完成后,我们就可以登录到容器中安装自己需要的软件或者服务。
9. 安装Docker
#安装最新版本的Docker
sudo apt install docker-ce docker-ce-cli containerd.io
#等待安装完成
#查看Docker版本
sudo docker version
#查看Docker运行状态
sudo systemctl status docker
#docker 命令补全工具
sudo apt-get install bash-completion
sudo curl -L https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker -o /etc/bash_completion.d/docker.sh
source /etc/bash_completion.d/docker.sh
#启动docker
sudo systemctl start docker
#查看 Docker 是否成功
docker info
#注意:通过tar包安装的Go,注意解压到/usr/local/这个目录再配置环境变量
10. Docker常用命令
- docker search 镜像名称 //搜索镜像
- docker pull 镜像名称:版本号 //拉取对应版本的镜像
- docker pull 镜像名称 //默认拉取最新的镜像
- docker images //查看本地已下载的镜像
- docker ps //查看正在运行的容器
- docker ps -a //查看所有的容器(包括run、stop、exited状态的)
- docker container ls //查看正在运行的容器
- docker rm 容器ID //只能删除没有在运行的容器
- docker rm -f 容器ID //可以删除正在运行的容器
- docker run -p 本地主机端口号:容器服务端口号 –name 容器名字 [-e 配置信息修改] -d 镜像名字
- docker start 容器ID //启动容器
- docker stop 容器ID //终止容器
- docker rmi 镜像名称orID //删除镜像
- docker rmi 镜像名称orI –force //强制删除镜像
11. Docker部署GO项目
- 项目创建
- mkdir demo_app
- go mod demo_app
- touch main.go
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("GET /posts/{id}", func(writer http.ResponseWriter, request *http.Request) {
id := request.PathValue("id")
fmt.Fprintf(writer, "docker 部署GO : id: %s", id)
})
fmt.Println("Starting server at http://localhost:8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
~
2. 运行 go run main.go //运行结果 Starting server at http://localhost:8080
3. 编写Dockerfile
# 使用官方的 Go 语言镜像作为基础镜像
# 这里使用 Go 1.22.6 版本的 Alpine Linux 镜像
FROM golang:1.22.6-alpine AS builder
# 设置工作目录为 /app
# 所有后续操作都会在这个目录下进行
WORKDIR /app
# 将当前项目目录的所有文件拷贝到容器的 /app 目录中
COPY . .
# 设置 Go 模块代理为 https://goproxy.cn(在中国加速模块下载),并下载项目的依赖
RUN go env -w GOPROXY=https://goproxy.cn,direct && go mod download
# 编译 Go 项目,生成可执行文件 demo_app
RUN go build -o demo_app
# 使用一个更小的基础镜像(Alpine)来运行应用程序
# Alpine 是一个极简的 Linux 发行版,适合部署阶段
FROM alpine:latest
# 安装 tzdata 包,确保支持时区的配置
RUN apk add --no-cache tzdata
# 设置工作目录为 /app
WORKDIR /app
# 从编译阶段的镜像中拷贝编译后的二进制文件到运行镜像中
COPY --from=builder /app/demo_app /app/demo_app
# 暴露容器的 8080 端口,用于外部访问
EXPOSE 8080
# 设置容器启动时运行的命令
# 这里是运行编译好的可执行文件 demo_app
CMD ["/app/demo_app"]
4. 构建docker镜像 :
docker build -t demp_app .
docker build:这是 Docker 用于构建镜像的命令。
-t simple-web-app:t 是 --tag 的缩写,用来给构建的 Docker 镜像命名。
.:指定了构建上下文的路径,. 表示当前目录,Docker 引擎会从当前目录读取 Dockerfile 以及所有相关的项目文件并打包进镜像中。
5. 运行docker容器
docker run -p 8080:8080 simple-web-app
docker run:基于指定的 Docker 镜像创建并启动一个容器实例。
-p 8080:8080:将本地主机的 8080 端口映射到容器的 8080 端口,以便你可以通过 localhost:8080 访问容器内的应用。
simple-web-app:基于 simple-web-app 镜像来创建并运行容器。
这样,Go 项目将会在本地的 8080 端口上运行。你可以通过浏览器访问 http://localhost:8080/posts/1,应该会看到 id: 1 的字样。
12. Docker compose
- 概述
- 在前面的
demo_app
项目中,我们只实现了一个简单的Web
服务,它并没有依赖任何第三方中间件。因此,只需要一个Docker
容器就可以完成整个项目的部署,过程相对简单。 - 然而,在实际的项目中,即使是类似的
Web
应用,往往也会需要依赖其他第三方中间件,例如数据库(如MySQL
、PostgreSQL
、MongoDB
)、缓存(如Redis
)、或者消息队列(如Kafka
)等。这些依赖服务需要与Web
应用协同工作,如果我们需要手动启动每个服务的Docker
容器,并且管理它们之间的启动顺序和网络配置,整个过程会非常繁琐且容易出错。 - 为了简化这些管理和配置工作,使得多服务应用的部署更加简便和一致,我们可以使用
Docker Compose
工具。Docker Compose
是Docker
的一个工具,允许我们通过编写一个简单的YAML
文件(通常命名为docker-compose.yml
),来描述多服务应用所需的容器、网络配置、卷等资源。借助这个配置文件,我们只需一条命令就可以启动所有相关的服务,使得整个流程更高效且易于管理。
- 在前面的
- 安装docker compose
- sudo apt-get update
- sudo apt-get install docker-compose-plugin
- docker compose version
- #更新,重复执行以上命令
- 引入 mongo 库
- go get github.com/chenmingyong0423/go-mongox
- main.go
package main
import (
"context"
"fmt"
"net/http"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/builder/query"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type Post struct {
mongox.Model `bson:",inline"`
Title string `bson:"title"`
Author string `bson:"author"`
Content string `bson:"content"`
}
// 示例代码,不是最佳的创建方式
func newCollection() *mongo.Collection {
client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://mongo:27017").SetAuth(options.Credential{
Username: "test",
Password: "test",
AuthSource: "db-test",
}))
if err != nil {
panic(err)
}
err = client.Ping(context.Background(), readpref.Primary())
if err != nil {
panic(err)
}
collection := client.Database("db-test").Collection("test_post")
return collection
}
func main() {
// 创建一个 *mongo.Collection 对象
mongoColl := newCollection()
// 使用 Post 结构体作为泛型参数创建一个 collection
postColl := mongox.NewCollection[Post](mongoColl)
http.HandleFunc("GET /posts/{id}", func(writer http.ResponseWriter, request *http.Request) {
id := request.PathValue("id")
post, err := postColl.Finder().Filter(query.Id(id)).FindOne(context.Background())
if err != nil {
fmt.Fprintf(writer, "docker compose error: %s", err.Error())
} else {
fmt.Fprintf(writer, "docker compose post: %v", post)
}
})
fmt.Println("Starting server at http://localhost:8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
5. 编写 MongoDB 脚本
mongosh -- "$MONGO_INITDB_DATABASE" <<EOF
db = db.getSiblingDB('admin')
db.auth('$MONGO_INITDB_ROOT_USERNAME', '$MONGO_INITDB_ROOT_PASSWORD');
db = db.getSiblingDB('$MONGO_INITDB_DATABASE')
db.createUser({
user: '$MONGO_USERNAME',
pwd: '$MONGO_PASSWORD',
roles:[
{
role: 'readWrite',
db: '$MONGO_INITDB_DATABASE'
}
]
});
EOF
6. 编写docker-compose.yaml 文件
version: '3.8'
services:
# 定义 simple-web-app 服务
web:
# 使用 Dockerfile 构建镜像
build: .
# 容器启动后暴露的端口,映射宿主机的8080端口到容器的8080端口
ports:
- "8080:8080"
# 依赖于 db 服务,确保 MongoDB 服务在 web 服务之前启动
depends_on:
- mongo
# 定义 MongoDB 服务
mongo:
# 使用官方的 MongoDB 镜像
image: mongo:latest
# 设置 MongoDB 初始化时的根用户名、密码和默认数据库
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
MONGO_INITDB_DATABASE: db-test
MONGO_USERNAME: test # 应用程序用户的名称
MONGO_PASSWORD: test # 应用程序用户的密码
# 暴露 MongoDB 的默认端口27017,便于外部访问
ports:
- "27017:27017"
# 使用 --auth 命令启动 MongoDB 以启用身份验证
command:
- --auth
# 使用卷来持久化数据库数据,避免容器删除时数据丢失
volumes:
- db_data:/data/db
# 将初始化 MongoDB 用户的脚本挂载到容器中,确保在启动时执行
- ./script/mongo-init.sh:/docker-entrypoint-initdb.d/mongo-init.sh
# 定义卷,用于持久化存储 MongoDB 的数据,避免数据在容器重启时丢失
volumes:
db_data:
7. 运行 docker-compose 命令
docker-compose up -d
#
构建 demo_app 的 Docker 镜像。
启动 MongoDB 服务,并通过 mongo-init.sh 初始化数据库、用户和权限。
启动 demo_app 容器。
#访问浏览器
http://192.168.2.32:8080/posts/1 或者 http://localhost:8080/posts/1
#stop服务
docker-compose down
#清除旧镜像和容器
docker-compose down && docker-compose up --build -d