神奇的容器——Docker
定义与作用
关于Docker的定义与用处,大家可以先看看下面视频大致了解一下我们为什么要使用Docker容器技术:https://www.bilibili.com/video/BV1aA4m1w7Ew/?vd_source=b4c665261a61efe281b3c1fa4e98ffe2
总的来说,Docker 就是一个工具,可以让你把 软件(比如你的代码、数据库、网站)和它需要的运行环境 一起打包成一个容器。容器直接共享电脑的操作系统,所以你可以把这个容器随便搬到任何电脑上运行,不用担心环境不一样导致程序出错(这样就不存在“代码在我这里能跑啊!”的借口了😁)
概念扫盲
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 | FROM openjdk:17 |
这样我们就创建了一个应用的镜像文件,以下是其他可供参考的参数:
关键字 | 作用 | 备注 |
---|---|---|
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
来列出主机上的所有镜像:
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
查看是否更改为指定地址
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 | # 1. 更新软件包 |
Docker部署MySQL
作为每个应用必备的数据库,在项目中使用docker部署mysql已经必不可少
以mysql 8.0.26版本为例:
1 | # 1. 拉取镜像 |
Docker部署Web应用
记得Springboot项目中的yaml配置文件需要把mysql的连接信息改成服务器而不是本地
方案一:拷贝jar包到服务器部署
- 编辑好项目的dockerfile
- Maven package 打包maven项目生产jar包
- 复制dockerfile 和 jar包到服务器的同一个文件夹下
- build 项目镜像
1 | docker build -t dockerlearn:1.0 . |
- 启动容器:
docker run -d --name docker-learn --restart always dockerlearn:1.0
方案二:idea 链接docker直接构建镜像启动容器
- IDEA内下载插件
2. 编辑配置,添加Docker Image服务,创建新服务器连接
- 选择SSH连接,认证方式选择密码,填入连接服务器的账号密码和服务器ip地址
- 再添加Dockerfile服务,填写dockerfile路径和镜像版本,以及配置运行选项:容器名称、绑定端口、运行选项…最后通过Command preview检查一下运行命令是否正确,最后添加执行前编译
- 使用maven命令快速搭建docker部署前条件
clean
:清除项目之前的构建产物(如target
目录)
package
:编译源代码、运行测试,并将项目打包为 JAR/WAR 等格式。
-U
:强制更新所有依赖(包括 SNAPSHOT 版本)
-DskipTests
:跳过单元测试的执行
Docker Compose
一个用于定义和运行多容器 Docker 应用的工具。通过 Compose,用户可以使用一个 docker-compose.yml
配置文件定义多个容器(服务),并可以通过一个命令启动这些容器
需完成项目的dockerfile文件编写,再进行以下操作
- 安装Docker Compose
1 | 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 |
- 编写docker-compose.yml
以mysql和web应用的部署为例:
1 | version: '3.1' |
详细指令说明可以参考:docker-compose使用指南
- 将dockerfile、jar包、docker-compose.yml文件放在同一个文件夹下,进入文件夹
- 执行
docker-compose up -d
(若项目镜像未编译,需先执行docker-compose build .
)
其他docker-compose命令:
1 | 列出本地 `docker-compose.yml` 文件里定义的正在运行的所有服务 |
Docker自动化部署
IDEA集成Docker容器管理工具
Github Action + Docker
原理:通过监听代码变化,触发定制任务,进行自动打包代码,镜像上传和登录服务器进行脚本执行,完成部署
- 在项目根目录创建
yml
文件,用于配置自动化流程任务
1 | mkdir .github |
- 编写yml 文件
1 | name: deploy |
- 之后每次更新代码只需push分支,就能出发自动化部署
Jenkins + Docker
这种方案做了解就行,目前我们接触到的业务和项目,都不需要这么大体量的工具。网络上有很多详细的介绍,可以自行搜索🔍
区别
以上三种部署的方案适用于不同的场景:
- 个人开发者/快速原型:IDEA集成
- 难以共享配置,不适合团队统一流程
- 开源项目/中小团队:Github Action
- 基于代码事件自动触发工作流
- 企业复杂环境:Jenkins
- 相比现代方案更重