定义与作用

关于Docker的定义与用处,大家可以先看看下面视频大致了解一下我们为什么要使用Docker容器技术:https://www.bilibili.com/video/BV1aA4m1w7Ew/?vd_source=b4c665261a61efe281b3c1fa4e98ffe2

总的来说,Docker 就是一个工具,可以让你把 软件(比如你的代码、数据库、网站)和它需要的运行环境 一起打包成一个容器。容器直接共享电脑的操作系统,所以你可以把这个容器随便搬到任何电脑上运行,不用担心环境不一样导致程序出错(这样就不存在“代码在我这里能跑啊!”的借口了😁)

概念扫盲

img

Dockerfile

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令说明

通过定义一系列命令和参数,Dockerfile 指导 Docker 构建一个自定义的镜像。

举个例子:

FROM:指定基础镜像为 openjdk:17(官方提供的 OpenJDK 17 运行环境)

WORKDIR:设置容器内的工作目录为 /app

VOLUME:声明一个挂载点 /tmp,用于存储临时文件

COPY:将宿主机当前目录下的 InsightNews-0.0.1-SNAPSHOT.jar 文件复制到容器的 /app 目录(由 WORKDIR 指定)

EXPOSE:声明容器运行时监听的端口为 8087(因为容器内部相当于一个新的服务器)

ENTRYPOINT:指定容器启动时执行的命令,即运行 JAR 文件(注意jar文件的名字不要写错了)

1
2
3
4
5
6
FROM openjdk:17
WORKDIR /app
VOLUME /tmp
COPY DockerLearn-0.0.1-SNAPSHOT.jar .
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "DockerLearn-0.0.1-SNAPSHOT.jar"]

这样我们就创建了一个应用的镜像文件,以下是其他可供参考的参数:

关键字作用备注
FROM指定父镜像指定dockerfile基于那个image构建
MAINTAINER作者信息用来标明这个dockerfile谁写的
LABEL标签用来标明dockerfile的标签,可以使用Label代替Maintainer,最终都是在docker image基本信息中可以查看
RUN执行命令执行一段命令,默认是/bin/sh格式:RUN command 或者 RUN [“command”, “param1”,”param2”]
CMD容器启动命令提供启动容器时候的默认命令,和ENTRYPOINT配合使用。格式CMD command param1 param2 或者CMD [“command”, “param1”,”param2”]
ENTRYPOINT入口一般在制作一些执行就关闭的容器中会使用
COPY复制文件build的时候复制文件到image中
ADD添加文件build的时候添加文件到image中,不仅仅局限于当前build上下文,可以来源于远程服务
ENV环境变量指定build时候的环境变量,可以在启动的容器的时候,通过-e覆盖。格式ENV name=value
ARG构建参数构建参数,只在构建的时候使用的参数,如果有ENV,那么ENV的相同名字的值始终覆盖arg的参数
VOLUME定义外部可以挂载的数据卷指定build的image那些目录可以启动的时候挂载到文件系统中,启动容器的时候使用 -v 绑定。格式VOLUME [“目录”]
EXPOSE暴露端口定义容器运行的时候监听的端口,启动容器的使用-p来绑定暴露端口。格式:EXPOSE 8080 或者 EXPOSE 8080/udp
WORKDIR工作目录指定容器内部的工作目录,如果没有创建则自动创建。如果指定/使用的是绝对地址,如果不是/开头那么是在上一条workdir的路径的相对路径
USER指定执行用户指定build或者启动的时候,用户在RUN、CMD、ENTRYPOINT执行的时候的用户
HEALTHCHECK健康检查指定监测当前容器的健康监测的命令,基本上没用,因为很多时候应用本身有健康监测机制
ONBUILD触发器当存在ONBUILD关键字的镜像作为基础镜像的时候,当执行FROM完成之后,会执行ONBUILD的命令,但是不影响当前镜像,用处也不怎么大
STOPSIGNAL发送信号量到宿主机该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出
SHELL指定执行脚本的shell指定RUN、CMD、ENTRYPOINT执行命令的时候,使用的shell

Image镜像

Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统

使用docker images来列出主机上的所有镜像:

img

REPOSITORY:表示镜像的仓库源

TAG:镜像的标签

IMAGE ID:镜像ID

CREATED:镜像创建时间

SIZE:镜像大小

  • 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,像 ubuntu 仓库源里有 15.10、14.04 等不同版本,所以我们使用 REPOSITORY:TAG 来定义不同的镜像

国内从 DockerHub 拉取镜像有时会遇到困难,此时可以配置镜像加速器

国内各大云服务商均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务。阿里云镜像获取地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors,登陆后,左侧菜单选中镜像加速器就可以看到你的专属地址了

  • Ubuntu16.04+、Debian8+、CentOS7:对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):{“registry-mirrors”:[“<地址>”]}
  • 验证加速器是否生效:执行docker info 查看是否更改为指定地址

img

Container容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等,容器在运行时与其他容器和宿主机共享操作系统内核,但容器之间的文件系统和进程是隔离的

常见选项说明:

-d:后台运行容器,例如 docker run -d ubuntu

-it:以交互式终端运行容器,例如 docker exec -it container_name bash

-t:为镜像指定标签,例如 docker build -t my-image

以下是操作容器的docker命令:

命令功能示例
docker run启动一个新的容器并运行命令docker run -d ubuntu
docker ps列出当前正在运行的容器docker ps
docker ps -a列出所有容器(包括已停止的容器)docker ps -a
docker build使用 Dockerfile 构建镜像docker build -t my-image .
docker images列出本地存储的所有镜像docker images
docker pull从 Docker 仓库拉取镜像docker pull ubuntu
docker push将镜像推送到 Docker 仓库docker push my-image
docker exec在运行的容器中执行命令docker exec -it container_name bash
docker stop停止一个或多个容器docker stop container_name
docker start启动已停止的容器docker start container_name
docker restart重启一个容器docker restart container_name
docker rm删除一个或多个容器docker rm container_name
docker rmi删除一个或多个镜像docker rmi my-image
docker logs查看容器的日志docker logs container_name
docker inspect获取容器或镜像的详细信息docker inspect container_name
docker exec -it进入容器的交互式终端docker exec -it container_name /bin/bash
docker network ls列出所有 Docker 网络docker network ls
docker volume ls列出所有 Docker 卷docker volume ls
docker-compose up启动多容器应用(从 docker-compose.yml 文件)docker-compose up
docker-compose down停止并删除由 docker-compose 启动的容器、网络等docker-compose down
docker info显示 Docker 系统的详细信息docker info
docker version显示 Docker 客户端和守护进程的版本信息docker version
docker stats显示容器的实时资源使用情况docker stats
docker login登录 Docker 仓库docker login
docker logout登出 Docker 仓库docker logout

Repository仓库

Docker 仓库是用来存储 Docker 镜像的地方,最常用的公共仓库是 Docker Hub。用户可以从 Docker Hub 下载镜像,也可以上传自己的镜像分享给其他人。除了公共仓库,用户也可以部署自己的私有 Docker 仓库来管理企业内部的镜像。

推送镜像到 Docker Hub:

1
docker push <username>/<image_name>

上手Docker

安装Docker

以Ubuntu为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 1. 更新软件包
sudo apt update
sudo apt upgrade

# 2. 安装docker依赖
apt-get install ca-certificates curl gnupg lsb-release

# 3. 添加Docker官方GPG密钥
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 4. 添加Docker软件源
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

# 5. 安装docker
apt-get install docker-ce docker-ce-cli containerd.io

# 6. 启动docker
systemctl start docker

# 7. 安装工具
apt-get -y install apt-transport-https ca-certificates curl software-properties-common

# 8. 验证是否安装成功
sudo docker version

Docker部署MySQL

作为每个应用必备的数据库,在项目中使用docker部署mysql已经必不可少

以mysql 8.0.26版本为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 1. 拉取镜像
docker pull mysql:8.0.26

# 2. 创建挂载目录
mkdir -p /home/mysql/{conf,data,log}

# 3. 创建配置文件
cd /home/mysql/conf
vim mysql.cnf

# 4. 配置文件内容
[client]
#设置客户端默认字符集utf8mb4
default-character-set=utf8mb4
[mysql]
#设置服务器默认字符集为utf8mb4
default-character-set=utf8mb4
[mysqld]
#配置服务器的服务号,具备日后需要集群做准备
server-id = 1
#开启MySQL数据库的二进制日志,用于记录用户对数据库的操作SQL语句,具备日后需要集群做准备
log-bin=mysql-bin
#设置清理超过30天的日志,以免日志堆积造过多成服务器内存爆满。2592000秒等于30天的秒数
binlog_expire_logs_seconds = 2592000
#解决MySQL8.0版本GROUP BY问题
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
#允许最大的连接数
max_connections=1000
# 禁用符号链接以防止各种安全风险
symbolic-links=0
# 设置东八区时区
default-time_zone = '+8:00'
按ESC键退出编辑模式,输入:wq保存并退出

# 5. 启动MySQL容器
docker run \
-p 3306:3306 \
--restart=always \
--name mysql \
--privileged=true \
-v /home/mysql/log:/var/log/mysql \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/conf/mysql.cnf:/etc/mysql/my.cnf \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:8.0.26

# 6. 查看容器运行状态
docker ps

# 7. 查看容器日志
docker logs <容器ID/容器名>

Docker部署Web应用

记得Springboot项目中的yaml配置文件需要把mysql的连接信息改成服务器而不是本地

方案一:拷贝jar包到服务器部署

  1. 编辑好项目的dockerfile
  2. Maven package 打包maven项目生产jar包
  3. 复制dockerfile 和 jar包到服务器的同一个文件夹下
  4. build 项目镜像
1
2
docker build -t dockerlearn:1.0 .
docker images #查看刚构建的镜像
  1. 启动容器:docker run -d --name docker-learn --restart always dockerlearn:1.0

方案二:idea 链接docker直接构建镜像启动容器

  1. IDEA内下载插件

img
2. 编辑配置,添加Docker Image服务,创建新服务器连接

img

img

  1. 选择SSH连接,认证方式选择密码,填入连接服务器的账号密码和服务器ip地址

img

img

18f1a602-1e54-424a-99fc-c88ff0498040

c4d9917c-26ff-4765-b204-dc77e8c24cbb

  1. 再添加Dockerfile服务,填写dockerfile路径和镜像版本,以及配置运行选项:容器名称、绑定端口、运行选项…最后通过Command preview检查一下运行命令是否正确,最后添加执行前编译

img

  1. 使用maven命令快速搭建docker部署前条件

clean:清除项目之前的构建产物(如target目录)

package:编译源代码、运行测试,并将项目打包为 JAR/WAR 等格式。

-U:强制更新所有依赖(包括 SNAPSHOT 版本)

-DskipTests:跳过单元测试的执行

img

img

Docker Compose

一个用于定义和运行多容器 Docker 应用的工具。通过 Compose,用户可以使用一个 docker-compose.yml 配置文件定义多个容器(服务),并可以通过一个命令启动这些容器

需完成项目的dockerfile文件编写,再进行以下操作

  1. 安装Docker Compose
1
2
3
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose -v #验证安装
  1. 编写docker-compose.yml

以mysql和web应用的部署为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
version: '3.1'  

services:
mysql:
image: mysql:8.0.26
container_name: mysql
restart: always
ports:
- "3306:3306"
volumes:
- /home/mysql/data:/var/lib/mysql
- /home/mysql/conf:/etc/mysql
- /home/mysql/log:/var/log/mysql
environment:
#数据库密码
- MYSQL_ROOT_PASSWORD=123456
#创建的库
- MYSQL_DATABASE=dockerlearn
#允许多IP连接数据库
- MYSQL_ROOT_HOST=%

dockerlearn:
image: dockerlearn:1.0
//build: . # 使用当前目录的Dockerfile构建镜像
container_name: docker-learn
ports:
- "8080:8080"
environment:
- DATABASE_HOST=mysql
- DATABASE_USER=root
- DATABASE_PASSWORD=123456
- DATABASE_NAME=dockerlearn
- DATABASE_PORT=3306
depends_on:
- mysql

详细指令说明可以参考:docker-compose使用指南

  1. 将dockerfile、jar包、docker-compose.yml文件放在同一个文件夹下,进入文件夹
  2. 执行docker-compose up -d(若项目镜像未编译,需先执行docker-compose build .

其他docker-compose命令:

1
2
3
4
5
6
7
8
9
10
11
# 列出本地 `docker-compose.yml` 文件里定义的正在运行的所有服务
docker-compose ps

# 查看服务的日志,这个命令会追踪服务的日志文件
docker-compose logs

# 停止所有服务,如果服务没有停止,可以使用 `docker-compose kill` 强制杀死服务
docker-compose stop

# 删除所有服务
docker-compose rm

Docker自动化部署

IDEA集成Docker容器管理工具

参考Docker部署Web应用的方案二

Github Action + Docker

原理:通过监听代码变化,触发定制任务,进行自动打包代码,镜像上传和登录服务器进行脚本执行,完成部署

  1. 在项目根目录创建 yml 文件,用于配置自动化流程任务
1
2
3
mkdir .github
mkdir .github/workflows
vim .github/workflows/deploy.yml

img

  1. 编写yml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
name: deploy
on:
# 触发条件为 push
push:
branches: kelsey
# 修改文件范围, 不在范围内不触发
paths:
- '.github/workflows/**'
- '__test__/**'
- 'src/**'

jobs:
build-and-deploy:
# 运行的环境
runs-on: ubuntu-20.04
# 步骤
steps:
- name: 拉取kelsey分支代码
uses: actions/checkout@v3
with:
ref: 'kelsey'

- name: 安装 Java 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Maven 打包
run: mvn clean package -DskipTests

- name: 在远程服务器上操作
uses: appleboy/ssh-action@v0.1.10
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.REMOTE_SSH_KEY }}
port: 22
script: |
ls -l /home/InsightNews/
cd /home/InsightNews
# 停止并移除容器和镜像
if docker container ls -a | grep -q "InsightNews"; then
docker stop InsightNews
docker rm InsightNews
fi
if docker image ls | grep -q "InsightNews"; then
docker rmi InsightNews
fi
echo "清理完成!"
# 构建新的 Docker 镜像
docker build -t insightnews .
# 运行新的 Docker 容器
docker run -d -e TZ=Asia/Shanghai -p 8087:8087 --name InsightNews --restart always insightnews
  1. 之后每次更新代码只需push分支,就能出发自动化部署

img

Jenkins + Docker

这种方案做了解就行,目前我们接触到的业务和项目,都不需要这么大体量的工具。网络上有很多详细的介绍,可以自行搜索🔍

区别

以上三种部署的方案适用于不同的场景:

  • 个人开发者/快速原型:IDEA集成
    • 难以共享配置,不适合团队统一流程
  • 开源项目/中小团队:Github Action
    • 基于代码事件自动触发工作流
  • 企业复杂环境:Jenkins
    • 相比现代方案更重