Docker入门笔记
Docker
相关资料可以移步至SpringCloud中的Docker查找,教程主要来源于黑马SpringCloud教程,后面看的GeekHour有部分截图在这里
简介与作用
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口
大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题:
- 依赖关系复杂,容易出现兼容性问题
- 开发、测试、生产环境有差异
Docker为了解决依赖的兼容问题的,采用了两个手段:
将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
将每个应用放到一个隔离容器去运行,避免互相干扰
Docker如何解决不同系统环境的问题?
- Docker将用户程序与所需要调用的系统(比如Ubuntu)函数库一起打包
- Docker运行到不同操作系统时,直接基于打包的函数库,借助于操作系统的Linux内核来运行
Docker是一个快速交付应用、运行应用的技术,具备下列优势:
- 可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统
- 运行时利用沙箱机制形成隔离容器,各个应用互不干扰
- 启动、移除都可以通过一行命令完成,方便快捷
Docker和虚拟机的区别
虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在 Windows 系统里面运行 Ubuntu 系统,这样就可以运行任意的Ubuntu应用了。
Docker仅仅是封装函数库,并没有模拟完整的操作系统
Docker和虚拟机的差异:
- docker是一个系统进程;虚拟机是在操作系统中的操作系统
- docker体积小、启动速度快、性能好;虚拟机体积大、启动速度慢、性能一般
Docker架构
镜像与容器
镜像(Image):Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像。
容器(Container):镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器进程做隔离,对外不可见。
DockerHub
开源应用程序非常多,打包这些应用往往是重复的劳动。为了避免这些重复劳动,人们就会将自己打包的应用镜像,例如Redis、MySQL镜像放到网络上,共享使用,就像GitHub的代码共享一样。
DockerHub:DockerHub是一个官方的Docker镜像的托管平台。这样的平台称为Docker Registry。
Docker架构
Docker是一个CS架构的程序,由两部分组成:
服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。
Docker在centos的安装
移步安装教程->Centos7安装Docker.md
查看docker运行状态
1 | docker version |
Docker的基本操作
镜像
镜像名称一般分两部分组成:[repository]:[tag]
在没有指定tag时,默认是latest,代表最新版本的镜像
Docker操作镜像结构图
大致结构图如下
拉取镜像
从docker hub查找对应镜像拉取指令
xshell执行该命令
1 | docker pull nginx |
查看现有镜像
1 | docker images |
导出与加载本地镜像
- 利用docker xx –help命令查看docker save和docker load的语法
- 使用docker save导出镜像到磁盘
- 使用docker load加载镜像
1 | docker save -o nginx.tar |
1 | docker load -i nginx.tar |
镜像操作指令
docker images
查看镜像
docker rmi
移除镜像
docker pull
拉取镜像
docker build -t 镜像名:版本 . (.为当前目录)
构建镜像
docker push
推送镜像
docker save
打包镜像
docker load
加载镜像压缩包
docker rmi –force [-f] $(docker images | grep 共有关键字 | awk ‘{print $3}’)
批量删除含共有关键字的镜像
容器操作
容器操作结构图
以运行一个nginx为例,可以通过dockerHub查找相关容器运行指令
1 | docker run --name containerName -p 80:80 -d nginx |
命令解读:
docker run :创建并运行一个容器
–name : 给容器起一个名字,比如叫做mn
-p :将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口
-d:后台运行容器
nginx:镜像名称,例如nginx
进入容器并修改容器内容(以修改nginx的html为例)
进入容器
1
docker exec -it mn bash
命令解读:
- docker exec :进入容器内部,执行一个命令
- -it : 给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
- mn :要进入的容器的名称
- bash:进入容器后执行的命令,bash是一个linux终端交互命令
进入html目录
1
cd /usr/share/nginx/html
修改html文件内容
1
2sed -i 's#Welcome to nginx#你是个什么东西😒#g' index.html
sed -i 's#<head>#<head><meta charset="utf-8">#g' index.html
注意:xec命令可以进入容器修改文件,但是在容器内修改文件是不推荐的
操作redis容器
运行redis
1 | docker run --name rd -p 6379:6379 -d redis redis-server --save 60 1 --loglevel warning |
进入redis 并运行redis-cli
1 | docker exec -it rd redis-cli |
执行redis操作
1 | set num 666 |
退出
1 | exit |
容器操作指令
docker logs
查看容器日志
添加 -f 参数可以持续查看日志
docker ps
查看容器状态码
docker exec -it [容器名] [要执行的命令]
进入容器
docker rm
删除容器
不能删除运行中的容器,除非添加 -f 参数
docker rm $(docker ps -aq)
删除所有未使用的容器
数据卷(容器数据管理)
容器与数据耦合的问题
数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的某个目录
我们就可以直接操作宿主机文件系统下的文件,从而使得容器与数据分离,解耦合,方便操作容器内数据,保证数据安全
数据卷操作
数据卷操作的基本语法:docker volume [COMMAND]
docker volume
命令是数据卷操作,根据命令后跟随的command
来确定下一步的操作:
create 创建一个volume
inspect 显示一个或多个volume的信息
ls 列出所有的volume
prune 删除未使用的volume
rm 删除一个或多个指定的volume
挂载数据卷
在创建容器时,可以通过 -v 参数来挂载一个数据卷到某个容器内目录,没有该数据卷时docker会帮我们创建一个
1 | docker run --name mn -v html:/usr/share/nginx/html -p80:80 -d nginx |
上述内容是将html数据卷挂载到容器的/usr/share/nginx/html目录
修改容器的数据卷内容
1 | # 查看html数据卷的位置 |
目录挂载
可以越过volumes直接将宿主机目录挂载起来
目录挂载与数据卷挂载的语法是类似的:
- -v [宿主机目录]:[容器内目录]
- -v [宿主机文件]:[容器内文件]
- -v [volume名称]:[容器内目录]
两者优劣:
- 数据卷挂载耦合度低,由docker来管理目录,但是目录较深,不好找
- 目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看
创建并运行一个MySQL容器,将宿主机目录直接挂载到容器
通过拉取(pull)或者本地有镜像直接加载(load)
1
docker load -i mysql.tar
查看镜像是否加载
1
docker images
创建目录用于挂载
/tmp/mysql/data
/tmp/mysql/conf
将自定义的配置文件放入conf目录下:hmy.cnf
运行容器,通过docker hub可以查询相关操作
查看mysql容器conf所在目录
通过
-e MYSQL_ROOT_PASSWORD=你的密码
可以设置mysql登陆密码完整执行命令
1
2
3
4
5
6
7
8docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-p 3306:3306 \
-v /tmp/mysql/conf:/etc/mysql/conf.d \
-v /tmp/mysql/data:/var/lib/mysql \
-d \
mysql:5.7.25Docker自定义镜像
简介
我们自己也可以构建Docker镜像,但需要首先了解镜像的结构
镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成
构建镜像其实就是将上图所示的各层打包形成一个镜像的过程
DockerFile
Dockerfile reference | Docker Documentation
Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer,一下是常见的指令
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM centos:6 |
ENV | 设置环境变量,可在后面指令使用 | ENV key value |
COPY | 拷贝本地文件到镜像的指定目录 | COPY ./mysql-5.7.rpm /tmp |
RUN | 执行Linux的shell命令,一般是安装过程的命令 | RUN yum install gcc |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
DockerFile示例
1 | # 指定基础镜像 |
构建Java项目
一、基于Ubuntu构建
新建一个空文件夹
1
mkdir docker-demo
拷贝jar文件到这个目录
拷贝jdk8.tar.gz文件到这个目录
创建或拷贝Dockerfile到这个目录
dockerfile文件内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 安装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 8090
# 入口,java项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar使用命令进入目录
1
cd /tmp/docker-demo
运行命令:docker build -t 镜像名:版本 . (.为当前目录)
使用docker run创建容器并运行
1
docker run --name javaweb -p 8090:8090 -d javaweb:1.0
二、基于java8构建Java项目
在DockerFile里,很多项目都是基于java8进行环境配置的,也就是说,下图所含内容都是重复性工作,每个项目都这么弄会重复工作,所以docker提供了镜像免去这些配置
新建一个空的目录,然后在目录中新建一个文件,命名为Dockerfile
1
2mkdir docker-demo
touch Dockerfile拷贝jar包到这个目录中
编写Dockerfile文件:
- 基于java:8-alpine作为基础镜像
- 将app.jar拷贝到镜像中
- 暴露端口
- 编写入口ENTRYPOINT
1
2
3
4FROM java:8-alpine
COPY ./docker-demo.jar /tmp/app.jar
EXPOSE 8090
ENTRYPOINT java -jar /tmp/app.jar使用docker build命令构建镜像
1
docker build -t javaweb:2.0 .
使用docker run创建容器并运行
1
docker run --name javaweb -p 8090:8090 -d javaweb:1.0
总结:
Dockerfile的本质是一个文件,通过指令描述镜像的构建过程
Dockerfile的第一行必须是FROM,从一个基础镜像来构建
基础镜像可以是基本操作系统,如Ubuntu。也可以是其他人制作好的镜像,例如:java:8-alpine
Docker-Compose
可爱的🐙章鱼镇楼
简介
当我们有多个微服务需要构建时,用自定义镜像的方式去一个个构建难免有点麻烦,Docker-Compose可以帮助我们批量处理,只需要定义好各个包的相关属性即可
Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器
Compose文件是一个文本文件(yaml格式),通过指令定义集群中的每个容器如何运行
DockerCompose的详细语法参考官网
下面的Compose文件就描述一个项目,其中包含两个容器:
- mysql:一个基于
mysql:5.7.25
镜像构建的容器,并且挂载了两个目录 - web:一个基于
docker build
临时构建的镜像容器,映射端口8090(注意:构建自己的项目默认会去找app.jar,所以打包后的java项目一定要命名为app)
1 | version: "3.8" |
DockerCompose文件可以看做是将多个docker run命令写到一个文件,只是语法稍有差异
安装
移步安装教程->Centos7安装Docker.md
构建微服务集群(重点)
PS:踩了一天的坑,差点🧚其中,😅
实现思路如下:
创建如下目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14-项目名
-微服务名1
-微服务名2
-微服务名...
-mysql
-conf
-data
docker-compose.yml我的项目如下所示:
每个微服务目录下新建Dockerfile文件,并填入以下内容
1
2
3FROM java:8-alpine
COPY ./app.jar /tmp/app.jar
ENTRYPOINT java -jar /tmp/app.jar含义是根据java:8-alpine进行打包,并构建当前目录下的app.jar包,所以,接下来你知道了吧,将每个微服务打包成名为app.jar包
用idea在每个微服务的pom.xml文件夹下修改或添加以下内容,用于将当前微服务打包为app.jar,记住,根目录下的就不要加这个东西了,在微服务里加
1
2
3
4
5
6
7
8
9<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>既然来到了idea,我们需要再改个东西,每个微服务请求的其他服务理应都该是服务名称,否则一旦部署到其他环境,ip地址改变,我们就无从下手了(当然肯定有办法的只是比较麻烦),这里的nacos以及mysql等一些需要请求的服务ip都改为服务名称
1
2
3
4spring:
datasource:
#url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false #用于docker部署设置的微服务名1
2
3
4
5
6spring:
cloud:
nacos:
#server-addr: localhost:8848 # Nacos地址
#server-addr: localhost:80 # nginx反向代理Nacos
server-addr: nacos:8848 # 用于docker部署设置的微服务名然后就是进行打包操作了,gogogo,在项目根目录执行package操作
然后,将打包后的各个jar包拖至前面创建好的哥哥微服务目录下
接下来配置下mysql,mysql目录下的conf目录是用于存储相关的配置文件,文件命名为
hmy.cnf
,文件具体内容可以从网上查找,也可以直接复制下面的data目录用于存储一些mysql的数据,这里先不管了,后面构建完再创建也行
1
2
3
4
5[mysqld]
skip-name-resolve
character_set_server=utf8
datadir=/var/lib/mysql
server-id=1000然后,进到docker-compose.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
26version: "3.2"
services:
nacos:
image: nacos/nacos-server
environment:
MODE: standalone
ports:
- "8848:8848"
mysql:
image: mysql:5.7.25
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- "$PWD/mysql/data:/var/lib/mysql"
- "$PWD/mysql/conf:/etc/mysql/conf.d/"
ports:
- "3306:3306"
userservice:
build: ./user-service
orderservice:
build: ./order-service
gateway:
build: ./gateway
ports:
- "10010:10010"至此,整体文件创建配置完成,下面就要到服务器上的配置了,整体目录结构如下
将整个目录上传至虚拟机,在目录根路径下利用
docker-compose up -d
来部署,你可以输入docker-compose --help
去查看相关操作,这时候,项目就会自动化构建并运行了还没完,这时候我们通过
docker-compose logs 某个服务名
会发现服务会报错,因为在这里,nacos启动比其他微服务慢了,导致其他项目启动时没发现nacos,无法注册服务导致抛出异常,所以在这里我们需要重启下其他微服务,重启前最好重启下nacos服务,保证在浏览器能访问到http://服务器地址:8848/nacos/index.html
后再进行下一步1
2docker-compose restart nacos
docker-compose restart 微服务1 微服务2 微服务...在上一步完成后,服务相关的设置就已经ok了,但是这时的mysql还没有数据,我们需要在自己电脑上将本地的数据进行sql导出,然后连接上linux里面的数据库,将数据导入
大功告成,浏览器输入地址享用吧,在这时你也可以将mysql的data目录进行备份处理,这样在其他的系统就可以直接拷贝过去,无需执行第十步了
Docker镜像仓库
简介
registry - Official Image | Docker Hub
镜像仓库( Docker Registry )有公共的和私有的两种形式:
- 公共仓库:例如Docker官方的 Docker Hub,国内也有一些云服务商提供类似于 Docker Hub 的公开服务,比如 网易云镜像服务、DaoCloud 镜像服务、阿里云镜像服务等。
- 私有仓库:用户在本地搭建的私有 Docker Registry,企业自己的镜像最好是采用私有Docker Registry来实现
安装并搭建私有镜像仓库
移步安装教程->Centos7安装Docker.md
推送镜像和拉取镜像
记住:记得重新打包(tag)时,一定要加上镜像仓库地址(如下)
tag本地镜像
1 | docker tag nginx:latest 你的ip:8080/nginx:1.0 |
推送镜像
1 | docker push 你的ip:8080/nginx:1.0 |
拉取镜像
1 | docker pull 你的ip:8080/nginx:1.0 |