一 参考黑马Docker的学习
安装Docker - 飞书云文档 (feishu.cn)
安装docker参考:
安装yum报错
二 Docker是什么
1 我看到一篇文章,写得很通透
原文链接:https://blog.csdn.net/javaeEEse/article/details/122109564
1.Docker的三个基本概念:
Image(镜像)
Container(容器)
Repository(仓库)
Docker的思想来自于集装箱,集装箱解决了什么问题?
在一艘大船上,可以把货物规整的摆放起来。并且各种各样的货物被集装箱标准化了,集装箱和集装箱之间不会互相影响。那么我就不需要专门运送水果的船和专门运送化学品的船了。只要这些货物在集装箱里封装的好好的,那我就可以用一艘大船把他们都运走。docker就是类似的理念。现在都流行云计算了,云计算就好比大货轮。docker就是集装箱.
还不懂得话,在这么理解,docker你理解为快递车.
那么快递车是不是有一个个包裹,包裹可以理解为一个镜像,镜像可以理解为一个Java类,而容器可以理解为Java类的实例。
类只有一个,但可以new出千千万万个实例对象。所以,镜像只是一个可以生成容器的东西,而容器才能让程序运行起来。
仓库的话,比如说,都应该用过git吧,完全可以理解为git,上传拉取操作
那么docker有什么好处呢?
最简单的一个例子,比如说,你在刚开始的一台服务器部署项目,那么部署项目一定要配置mysql等环境是吧
那么现在你要吧这个项目迁移到另一台服务器上,又要重写在另一台服务器上重写配置mysql等环境.可能会出现版本错乱等错误,很麻烦
那么现在第一次部署项目的时候,把项目等环境直接放进docker里面,下次你要迁移项目到另一台服务器上,自己把docker镜像上传到docker仓库上,然后再另一台服务器拉取就直接O了,这只是好处之一
2 Docker的运行图
Docker有一套自己维护的仓库,叫做镜像仓库,里面有各种的绿色安装包(开包即用的),由Docker开发公司维护。拿使用Mysql为例子,刚开始我们发送命令到Docker的守护进程,会安装Mysql的Image(镜像),然后就可以使用Mysql了。使用Mysql时,每一个Mqsql服务器都会被包装成一个Container(容器),使其相互独立,互不影响。
3 总结
问 : Docker是做什么的?
Docker可以帮助我们下载应用镜像,创建并运行镜像的容器,从而快速部署应用
问 :什么是镜像?
将应用所需的函数库、依赖、配置等与应用一起打包得到的就是镜像
问 :什么是容器?
为每个镜像的应用进程创建的隔离运行环境就是容器
问 :什么是镜像仓库?
存储和管理镜像的服务就是镜像仓库, DockerHub是目前最大的镜像仓库,其中包含各种常见的应用镜像
三 命令
1 解读入门案例:docker安装mysql
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql
docker run :创建并运行一个容器,-d 是让容器在后台运行
--name mysql :给容器起个名字,必须唯一
-p 3306:3306 :设置端口映射
什么是映射呢? 我们在创建mysql容器后,我们外部是无法直接访问mysql的。容器一创建,就会有自己的ip地址,端口号,就像一台电脑一样。但是我们能访问到创建容器的电脑的ip地址,通过这台电脑的端口号映射,我们就能间接访问到创建的mysql
-e KEY=VALUE :是设置环境变量
-e MYSQL_ROOT_PASSWORD=123 设置密码,必须设置的配置,还有其他配置可选择,但不是必须的
mysql :指定运行的镜像的名字
我们用docker找镜像的时候,就是按照这个来找。这个叫做镜像名称。
镜像名称一般分两部分组成:[repository]:[tag]。 其中repository就是镜像名 tag是镜像的版本 在没有指定tag时,默认是latest,代表最新版本的镜像
2 常见命令
Docker最常见的命令就是操作镜像、容器的命令,详见官方文档:
Reference documentation | Docker Docs
docker build: 为docker建立私人镜像
docker save:将本地镜像打包
docker load : 将打包好的镜像加载到本地镜像内
docker images:查询本地所有镜像
docker rmi : 删除镜像 rmi:remove images
docker ps: 查询容器进程状态 ps:proceed status -a 看所有的容器,包括未启动的
其他看图应该可以理解
docker exec : 进入容器内执行操作 实例:docker exec -it nginx bash
-it:表示交互访问
bash:表示以命令行窗口访问
图片上没有:
退出容器 exit
查询容器详细信息 docker inspect
docker run -d :在后台运行
另外
docker 有其他较多的参数 , 需要注意
3 命令别名
# 修改/root/.bashrc文件
vi /root/.bashrc
内容如下:
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
对于docker的vi编辑器
source /root/.bashrc
四 数据卷:
1 案例需求
创建Nginx容器,修改nginx容器内的html目录下的index.html文件内容 将静态资源部署到nginx的html目录。
在我们进入nginx容器时,他虽然搭载了运行nginx的必要资源,但是它除了必要的资源什么都没有,包括vi编辑器。所以我们不能在nginx容器内修改index.html.这时候就要用到数据卷。
问 : 什么是数据卷?
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。
数它将宿主机目录映射到容器内目录,方便我们操作容器内文件,或者方便迁移容器产生的数据。
简单的来说,当我们做了这个映射桥梁后,双方中一方有修改,另一方也会随之修改。
注意:1 当创建了数据卷后,会在宿主机/var/lib/docker/volumes下创建对应的数据源,这是固定的路径。
2 数据卷是独立于容器的一个生命周期,即使删除了容器,主要目录不改变,数据卷也依然存在。如果不要某个数据卷,删除就可以了。
2 docker volume (数据卷)的命令
命令 | 说明 | 文档地址 |
---|---|---|
docker volume create | 创建数据卷 | |
docker volume ls | 查看所有数据卷 | |
docker volume rm | 删除指定数据卷 | |
docker volume inspect | 查看某个数据卷的详情 | |
docker volume prune | 清除数据卷 |
3 挂载数据卷到数据卷目录的命令
# 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
4 挂载数据卷到本地任意一个文件的命令
这里挂载到本地root下
问题:在上面挂载到容器目录,可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:
# 挂载本地目录 -v 本地目录:容器内目录
# 挂载本地文件 -v 本地文件:容器内文件
注意:本地目录必须以“/”或 "./" 开头,如果直接以名称开头,会被识别为数据卷而非本地目录
-v mysql : /var/lib/mysql 会被识别为一个数据卷叫mysql
-v ./mysql : /var/lib/mysql 会被识别为当前目录下的mysql目录
五 自定义镜像
1 重温什么是镜像
镜像就是包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。
2 镜像结构
要想自己构建镜像,必须先了解镜像的结构。
之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。
要想自己构建镜像,必须先了解镜像的结构。
之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。
举个例子,我们要从0部署一个Java应用,大概流程是这样:
-
准备一个linux服务(CentOS或者Ubuntu均可)
-
安装并配置JDK
-
上传Jar包
-
运行jar包
那因此,我们打包镜像也是分成这么几步:
-
准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)
-
安装并配置JDK
-
拷贝jar包
-
配置启动脚本
上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。
但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。
例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。我们在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个Java项目的镜像结构如图所示
3 Dockerfile
由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。
而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:
https://docs.docker.com/engine/reference/builder/
其中的语法比较多,比较常用的有:
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 |
|
ENV | 设置环境变量,可在后面指令使用 |
|
COPY | 拷贝本地文件到镜像的指定目录 |
|
RUN | 执行Linux的shell命令,一般是安装过程的命令 |
|
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/ COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装JDK
RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \ && mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8 ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]
以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。
所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了:
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口 ENTRYPOINT ["java", "-jar", "/app.jar"]
是不是简单多了。
当Dockerfile文件写好以后,就可以利用命令来构建镜像了。
# 进入镜像目录
cd /root/demo
# 开始构建
docker build -t docker-demo:1.0 .
- docker build : 就是构建一个docker镜像
- -t docker-demo:1.0 :-t参数是指定镜像的名称(repository和tag)
- . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo
4 实战
步骤一 :编写Dockerfile文件
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
现在root下Demo包有一个jar包和Dockerfile文件
步骤二 执行Dockerfile启动代码
[root@localhost ~]# cd demo
[root@localhost demo]# docker build -t docker-demo:1.0 .
[+] Building 32.7s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 359B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 16.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:3546a17e6fb4ff4fa681c38f3f6644efd393f9bb7ed6ebbd85f06065f5d570ed 15.4s
=> => resolve docker.io/library/openjdk:11.0-jre-buster@sha256:3546a17e6fb4ff4fa681c38f3f6644efd393f9bb7ed6ebbd85f06065f5d570ed 0.0s
=> => sha256:c4cc477c22ba7abce860198107408434dd7bd73ddbaf82f1e69ab941b9979405 50.44MB / 50.44MB 9.4s
=> => sha256:077c54d048f1f1a1f28079caa54bf5d99803f937ffe5c1dc6e207698f70b4e74 7.83MB / 7.83MB 4.3s
=> => sha256:0368544993b2deeeffdd19463cdf92ec4e39f83073de5de316f9f5c725ab403f 10.00MB / 10.00MB 5.9s
=> => sha256:3546a17e6fb4ff4fa681c38f3f6644efd393f9bb7ed6ebbd85f06065f5d570ed 549B / 549B 0.0s
=> => sha256:77dbc78717b5c1d2a6e2b6b47d266a81cb4ac024a8eba8ad135adcb0dbb32f0d 1.58kB / 1.58kB 0.0s
=> => sha256:57925f2e4cff6558a1d93c5bdd14820dc7f98141233d825572c554c50337b11d 7.52kB / 7.52kB 0.0s
=> => sha256:d2b3c389e55f5873bbaaed0e20d00ccb964d339e3e1a762baedc1997829274f5 5.53MB / 5.53MB 9.8s
=> => sha256:7fde22603cbd4234a15d25d9594d93f990480c1406b8be5c5e71e2d611fac1d0 211B / 211B 6.3s
=> => sha256:e540594d7c4708c6fe8ea4640e8269b2bb2f8ad11bae89133eddc031c7dcc12f 46.84MB / 46.84MB 14.0s
=> => extracting sha256:c4cc477c22ba7abce860198107408434dd7bd73ddbaf82f1e69ab941b9979405 2.9s
=> => extracting sha256:077c54d048f1f1a1f28079caa54bf5d99803f937ffe5c1dc6e207698f70b4e74 0.3s
=> => extracting sha256:0368544993b2deeeffdd19463cdf92ec4e39f83073de5de316f9f5c725ab403f 0.3s
=> => extracting sha256:d2b3c389e55f5873bbaaed0e20d00ccb964d339e3e1a762baedc1997829274f5 0.2s
=> => extracting sha256:7fde22603cbd4234a15d25d9594d93f990480c1406b8be5c5e71e2d611fac1d0 0.0s
=> => extracting sha256:e540594d7c4708c6fe8ea4640e8269b2bb2f8ad11bae89133eddc031c7dcc12f 1.4s
=> [internal] load build context 0.2s
=> => transferring context: 17.70MB 0.2s
=> [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone 0.4s
=> [3/3] COPY docker-demo.jar /app.jar 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:851d8aa0206f568f1c4b6f9013aa4c1352fd13193dc71aad0d918122cde17089 0.0s
=> => naming to docker.io/library/docker-demo:1.0 0.0s
构建镜像成功
六 网络
问题引入:
Java项目往往需要访问其它各种中间件,例如MySQL、Redis等。而这些中间件处于不同的容器中。现在,我们的容器之间能否互相访问从而使用其他中间件呢?
我们可以使用网络的知识。
从这张图可以看到,只要不同的容器连到相同的网络上,他们就可以相互访问。
在默认网络上我们只能通过ip地址来相互访问。容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。
我们必须借助于docker的网络功能来解决这个问题。在docker内,我们自己创建的自定义网络是可以通过容器名互相访问,这就解决了ip变化的问题。
注意:可以不用起别名!!!
网络常见命令
命令 | 说明 | 文档地址 |
---|---|---|
docker network create | 创建一个网络,dfsd | |
docker network ls | 查看所有网络 | |
docker network rm | 删除指定网络 | |
docker network prune | 清除未使用的网络 | |
docker network connect | 使指定容器连接加入某网络 | |
docker network disconnect | 使指定容器连接离开某网络 | |
docker network inspect | 查看网络详细信息 |
七 实战!!!项目部署
1 部署java项目
步骤一 将java项目用maven打包放在linux指定目录下
打开idea 点击父工程 点击package 这里需要禁掉text 跳过测试的打包 不然会报错
打包好之后会在打包的包下看到target文件夹,打包的文件都在里面
最后放在特定的文件夹 这里部署了service 和 dockerfile
步骤二 运行dockerfile构建jar包的镜像
docker build -t hmall .
步骤三 创建容器 顺便配网
docker run -d --name hm -p 8080:8080 --network myNW hmall
2 部署mysql和nginx 上面有
3 DockerCompose
1 问题引入 以及 DockerCompose介绍
大家可以看到,我们部署一个简单的java项目,其中包含3个容器:
-
MySQL
-
Nginx
-
Java项目
而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止3个。如果还像之前那样手动的逐一部署,就太麻烦了。
而Docker Compose就可以帮助我们实现多个相互关联的Docker容器的快速部署。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。
docker-compose.yml文件的基本语法可以参考官方文档:
https://docs.docker.com/compose/compose-file/compose-file-v3/
2 举例
docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与docker run
参数非常相似。
举例来说,用docker run部署MySQL的命令如下:
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v ./mysql/data:/var/lib/mysql \
-v ./mysql/conf:/etc/mysql/conf.d \
-v ./mysql/init:/docker-entrypoint-initdb.d \
--network hmall
mysql
如果用docker-compose.yml
文件来定义,就是这样:
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
networks:
- new
networks:
new:
name: hmall
对比如下:
docker run 参数 | docker compose 指令 | 说明 |
---|---|---|
--name | container_name | 容器名称 |
-p | ports | 端口映射 |
-e | environment | 环境变量 |
-v | volumes | 数据卷配置 |
--network | networks | 网络 |
3 命令
# 5.启动所有, -d 参数是后台启动
docker compose up -d