Docker介绍
物理机
在讲docker之前,先介绍一下物理机,发展到虚拟化时代的过程
物理机时代是计算机科学和信息技术的早期阶段,也是计算机系统的基础。在这个时代,计算机应用程序和操作系统都运行在物理硬件上,没有虚拟化或抽象层。每个计算任务都需要运行在单独的物理机上,资源分配和管理比较困难,也容易导致资源浪费。
虚拟机
为了克服物理机资源的浪费和管理难题,服务器虚拟化技术开始兴起。VMware 公司在2001年推出了第一个商用虚拟化产品,允许在单个物理机上运行多个虚拟机(VM)。每个虚拟机是一个独立的虚拟操作系统实例,它们共享物理机的资源。这种虚拟化技术极大地提高了资源利用率,并简化了管理。
我们现在在Windows操作系统上安装Linux操作系统都是通过 VMware Workstation 上通过虚拟机的镜像文件来安装虚拟机,这些虚拟机共用我们宿主机的硬件资源,我们就可以在一个宿主机上开启多个虚拟机部署多个app
但是虚拟化也是有局限性的,每一个虚拟机都是一个完整的操作系统,要分配系统资源,虚拟机多道一定程度时,操作系统本身资源也就消耗殆尽,或者说必须扩容。
容器化
为了解决应用部署时减少对硬件资源的浪费,容器化技术如Docker和Kubernetes兴起,它们提供了更轻量级的虚拟化方式,将应用程序和其依赖项打包成容器,以便在任何支持容器的环境中运行。容器与虚拟机相比更轻量级,它们共享主机操作系统的内核,只包含应用程序及其依赖项,因此更加节省资源。
Docker是实现容器化的一种方式,我们只需要使用相应的镜像文件,也就是将业务代码运行的环境,整体打包为单个的文件,就可以开启一个容器。下图是docker镜像分层结构
基础层(Base Layer) - Kernel:
- 基础层是 Docker 镜像的最底层,通常包含操作系统的内核(Kernel)。内核是操作系统的核心部分,负责管理硬件资源、进程管理和系统调用等底层功能。基础层一般就是我们的宿主机的内核,因此我们下载的docker镜像并不包括操作系统内核,因此文件比虚拟机镜像文件小,因为它只包括发行版,依赖和应用程序。
中间层(Intermediate Layers) - Debian 操作系统:
- 在基础层之上,可以有一个或多个中间层,代表了对基础层进行的修改和添加。对于 Debian 操作系统来说,这些中间层包含了 Debian 的用户空间组件,如文件系统、系统库、工具等。这些中间层可能包括 Debian 的软件包和配置,用于构建一个完整的 Debian 环境。它就是发行版,我们基于宿主机的Linux内核,就可以通过docker安装不同的发行版(ubuntu,centos...)来使用不同的Linux操作系统。
顶层(Top Layer) - Emacs 应用程序:
- 顶层是最终的镜像层,包含了您想要在容器中运行的 Emacs 应用程序。这个层包括了 Emacs 的二进制文件、配置文件、插件和用户数据。这是容器的实际文件系统,容器可以在其中修改并运行 Emacs。只有这一层是可以被修改的。
这样,整个 Docker 镜像分层结构就形成了。基础层提供了底层的操作系统内核,中间层添加了操作系统的用户空间组件(Debian),顶层包含了应用程序(Emacs)。每个层都是只读的,只有顶层是可写的,允许容器在其中运行和修改应用程序。
部署web应用
在本地开发了应用程序,它很可能有很多的依赖环境或包,甚至对依赖的具体版本都有严格的要求,当开发过程完成后,我们希望将应用程序部署到web服务器。这个时候必须确保所有依赖项都安装正确并且版本也完全相同,否则应用程序可能会崩溃并无法运行。如果想在另一个web服务器上也部署该应用程序,必须从头开始重复这个过程。这种场景就是Docker发挥作用的地方。
对于运行我们应用程序的主机,不管是笔记本电脑还是web服务器,我们唯一需要做的就是运行一个docker容器平台。从此以后,就不需要担心使用的是MacOS,Ubuntu还是其他。只需定义一次应用,即可随时随地运行。
我们要用docker部署web应用,就是要自己实现每一层的定制,然后构建成一个镜像文件,通过这个我们自己构建的镜像文件,就可以把我们的web应用部署到容器中。而定制每一层,就是通过写Dockerfile文件来实现。
Dockerfile
Dockerfile 是用于定义 Docker 镜像构建过程的文本文件。它包含了一系列命令,用于描述如何构建镜像。以下是 Dockerfile 中常用的一些命令:
FROM:指定基础镜像。它是 Dockerfile 的第一个命令,用于指定构建新镜像的起点。例如:
FROM ubuntu:20.04
MAINTAINER:指定镜像的维护者信息。虽然不是必需的,但可以提供有关镜像的相关信息。
RUN:在容器内执行命令。它可以用于在构建过程中运行各种命令,例如安装软件包、配置环境等。例如:
RUN apt-get update && apt-get install -y nginx
COPY 和 ADD :用于将文件从主机复制到容器内。
COPY
用于简单地复制文件,而ADD
具有一些额外的功能,如自动解压缩归档文件。例如:
COPY ./app /app
WORKDIR:设置容器内的工作目录。这可以用于指定容器中命令的执行路径。例如:
WORKDIR /app
EXPOSE:声明容器监听的端口。它不会实际打开端口,但可以在运行容器时提供端口映射。例如:
EXPOSE 80
CMD 和 ENTRYPOINT :定义容器启动时执行的命令。
CMD
定义了容器的默认命令,可以在运行容器时被覆盖。ENTRYPOINT
也定义了容器的启动命令,但不会被覆盖,除非在运行容器时使用--entrypoint
参数。例如:
CMD ["nginx", "-g", "daemon off;"]
ENV:设置环境变量。可以用于在容器内定义环境变量,以便应用程序在运行时使用。例如:
ENV APP_VERSION=1.0
这些是 Dockerfile 中的一些常用命令。Dockerfile 还支持其他命令和更高级的功能,可以根据具体需求进行使用。通过组合这些命令,您可以定义 Docker 镜像的构建过程,使其能够在不同的环境中正确运行您的应用程序。
简单代码demo
通过一个简单的web服务看一下它是怎么通过docker部署的
go
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", hello)
server := &http.Server{
Addr: ":8888",
}
fmt.Println("server startup...")
if err := server.ListenAndServe(); err != nil {
fmt.Printf("server startup failed, err:%v\n", err)
}
}
func hello(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("hello world"))
}
编写Dockerfile
在demo的同目录下,新建一个Dockerfile,并加入以下内容
ini
# 基础镜像golang:alpine,这个镜像运行的是alpine Linux发行版,该发行版的大小很小并且内置了Go
FROM golang:alpine
# 为我们的镜像设置必要的环境变量
ENV GO111MODULE=on \
GOPROXY=https://goproxy.cn,direct \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
# 移动到工作目录:/build
WORKDIR /build
# 将代码复制到容器中
COPY . .
# 将我们的代码编译成二进制可执行文件app
RUN go build -o app .
# 移动到用于存放生成的二进制文件的 /dist 目录
WORKDIR /dist
# 将二进制文件从 /build 目录复制到这里
RUN cp /build/app .
# 声明服务端口
EXPOSE 8888
# 启动容器时运行的命令
CMD ["/dist/app"]
构建镜像
在项目目录下,执行下面的命令创建镜像,并指定镜像名称为xx_goweb_app:
docker build . -t xx_goweb_app
等待构建过程结束,输出如下提示:
erlang
...
Successfully built 90d9283286b7
Successfully tagged xx_goweb_app:latest
现在我们已经准备好了镜像,但是目前它什么也没做。我们接下来要做的是运行我们的镜像,以便它能够处理我们的请求。运行中的镜像称为容器。
执行下面的命令来运行镜像:
arduino
docker run -p 8888:8888 xx_goweb_app
标志位-p
用来定义端口绑定。由于容器中的应用程序在端口8888上运行,我们将其绑定到主机端口也是8888。如果要绑定到另一个端口,则可以使用-p $HOST_PORT:8888
。例如-p 5000:8888
。
现在就可以测试下我们的web程序是否工作正常,打开浏览器输入http://127.0.0.1:8888
就能看到我们事先定义的响应内容如下:
hello world
Docker Compose模式
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。它允许您使用一个单独的文件(称为 docker-compose.yml
)来配置和启动多个 Docker 容器,这些容器可以协同工作以构建完整的应用程序。我在windows安装了Docker Desktop,Docker Compose 已经预安装在Docker Desktop中,所以不需要额外安装,除此情况需要安装Docker Compose,方法自行google
类似我们写一个商品微服务,它不仅有web服务,还需要使用到mysql和consul注册中心,这个时候我们就需要用到两个容器来协同工作部署这个微服务,通过 Docker Compose 部署包含微服务和 mysql的应用程序是一种常见的做法。
首先在项目目录下写好dockerfile文件并构建打包成镜像,并且把consul和mysql镜像也下载好
然后编写docker-compose.yaml文件
yaml
version: '3'
services:
go-service:
# build:
# context: .
# dockerfile: Dockerfile
image: goods_service2
# ports:
# - 8382:8382
volumes:
- ./conf:/conf
restart: always
depends_on:
- mysql
- consul
networks:
- my-network
mysql:
image: mysql:latest
restart: always
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=goods_service
- MYSQL_USER=fengmi
- MYSQL_PASSWORD=123456
networks:
- my-network
consul:
image: consul:1.10.3
restart: always
ports:
- 8500:8500
networks:
- my-network
networks:
my-network:
这里我们用文件映射./conf:/conf ,这样就可以在宿主机的配置文件修改容器内的配置文件,mysql下的environment可以乱填,不需要你去mysql容器中创建数据库用户名密码啥的,他自己帮你完成好了。并且配置一个network,这样可以让三个容器共享一个网络。
终端运行
docker-compose up -d
这样容器就部署成功了