Docker是基于go开发的
一、为什么使用docker
带着环境安装到Docker上,解决环境问题;解决了集群问题
镜像:将代码,Redis、、、等环境打包成一个镜像,在其他地方可以直接运行,无需在重新安装软件、代码;将正确的环境打包成镜像,直接运行,理念是一次打包处处运行,“一次封装,处处运行”
只需要一次配置好环境,换到其他的机子上就可以一键运行,大大简化了操作
四个集装箱(部署四个软件),各自独立,放到一个镜像当中,运行镜像即可
二、Docker三要素:仓库、镜像、容器
容器:集装箱就是一个容器,每一个容器当中安装我们要需要的软件,Docker就是鲸鱼,背上有几个集装箱就有几个容器
虚拟机:模拟的是整套操作系统(模拟的操作系统、软硬件—虚拟硬件,然后在硬件上虚拟软件操作系统),但是启动时间时分钟级别的,Docker启动时秒级别的;
Docker模拟的是操作系统,直接运行在宿主机上的(没有进行硬件虚拟),没有虚拟自己的内核,用的是宿主机的,所以启动快;容器之间是相互隔离的,每个容器由自己的文件系统,容器之间进程不会相互影响,能区分计算资源
运行环境的打包封装,这饿环境的一个整体就是镜像,DockerHub上就是存镜像的,
从仓库拉一个应用到本地就是镜像(Image),某一个镜像的实例就是一个集装箱容器,各自独立的容器就是一个一个的环境(Redis、Ngnix)
1、镜像
镜像(Image):Docker镜像就是一个只读的模版,镜像可以用来创建Docker容器,一个镜像可以创建很多容器—类
2、容器
容器(Container):镜像的实例—对象,Docker利用容器运行一个或一组应用,容器是用镜像创建的运行实例,可以对容器进行启动、开始、停止、删除;每个容器都是相互隔离的、保证安全的平台
可以吧容器看成是一个简易版本的Linux环境(包括root用户权限、进程空间、用户空间、网络空间等)和运行在其中的程序
容器的定义和镜像几乎一摸一样,也是一堆层的统一视角,唯一的区别是,容器的最上面那一层是可读可写的
容器是一个运行时环境,可以看成是鲸鱼上一个个的集装箱。
3、仓库
仓库(Repository):仓库是存放镜像文件的场所,仓库和仓库注册服务器是有区别的,仓库注册服务器上面存放着多个仓库,每个仓库又包含多个镜像,每个镜像又不同的标签(tag)
仓库分为公共仓库(public)和私有仓库(private)2种,最大的公共仓库是Docker Hub(https://hub.docker.com)—在国外,特别慢,存放了数量庞大的镜像供用户下载,国内的公共开源镜像又阿里云、网易云等
Docker本身是一个容器运行载体,或者称之为管理引擎,我们把应用程序和配置文件打包成包,形成一个可交付的运行环境,这个打包好的运行环境就似乎是一个镜像,只有通过镜像才可以生成Docker容器
镜像可以看成是容器的模版,Docker根据Image文件生成容器的实例,同一个镜像文件,可以生成多个同时运行的容器实例。
镜像文件生成的容器实例,本身也是一个文件,称为镜像文件
一个容器运行一种服务,当我们需要的时候,就可以通过Docker客户端创建一个对应的运行实例,也就是我们的容器
至于仓库,也就是存放镜像的地方,我们可以吧镜像发布到仓库中,需要的时候从仓库中拉下来救可以啦
平台架构图如下所示:

三、指令
1、docker相关–帮助启动类命令
# 启动
$ systemctl start docker
# 停止
$ systemctl stop docker
# 重启
$ systemctl restart docker
# 查看状态
$ systemctl status docker
# 开机自启
$ systemctl enable docker
# docker信息
$ docker info
# 帮助
$ docker --help
# 具体帮助
$ docker 具体指令 --help
2、镜像
# 查看所有镜像
$ docker images
# 查看远程镜像
$ docker search 镜像名
# 下载镜像
$ docker pull 镜像名
# 查看 镜像/容器/数据卷所占用的内存空间
$ docker system df
# 删除镜像
$ docker rmi 镜像名
# 强制删除镜像
$ docker rmi -f 镜像名
虚悬镜像:仓库名和tag都是空的镜像,一般是由于构建镜像的时候出问题导致的,这种镜像删除就好了
3、容器
# 运行ubunto:latest镜像,并开启交互式模式启动一个容器,在容器内部执行/bin/sh指令,推出使用exec;
$ docker run -it ubunto /bin/sh
# 给容器起名字
$ docker run -it --name="myubunto" ubunto /bin/sh
# 后台方式启动容器
$ docker run -d --name="myubunto" ubunto
# 列出所有正在运行的容器
$ docker ps
# 列出所有正在运行/历史运行的容器包括挂了的容器)
$ docker ps -a
# 列出最近创建的容器(包括挂了的容器)
$ docker ps -l
# 列出最近创建的3个容器(包括挂了的容器)
$ docker ps -n 3
# 退出容器--容器关闭
$ exec
# 退出容器--容器不关闭
$ ctrl+p+q
# 启动已经停止运行的容器
$ docker start 容器ID/名字
# 重启容器
$ docker restart 容器ID/名字
# 关闭容器
$ docker stop 容器ID/名字
# 强制停止容器
$ docker kill 容器ID/名字
# 删除已停止的容器
$ docker rm 容器ID/名字
# 查看容器运行日志
$ docker logs 容器ID
# 查看容器内部运行的进程
$ docker top 容器ID
# 查看容器内部情况
$ docker inspect 容器ID
exec和attach的区别
# 使用exit退出不会关闭容器(一般进入容器当中查看信息)
docker exec -it 容器ID /bin/sh
# 使用exit退出会关闭容器
docker attach 容器ID
从镜像的角度看,可以把容器看成是简易版本的Linux环境,
# 将容器内的内容拷贝到宿主机上
$ docker cp 容器ID:容器内路径 宿主机路径
# 将容器拷贝到宿主机上,归档成一个tar包
$ docker export 容器ID > 文件名.tar
eg: docker export efewtwe1231 > ubunto.tar
# 根据tar包的内容创建一个新的系统并导入成镜像(即新建一个镜像)
$ cat 文件名.tar | docker import - 镜像用户/镜像名:版本号
eg: cat ubunto.tar | docker import - techen/ubanto:3.7
四、Docker仓库
镜像是只读的,容器是可写的,一般在容器当中新增功能,然后使用commit指令生成新的镜像
# 提交镜像:提交之后成为了一个新的镜像
$ docker commit
# 提交镜像:提交之后成为了一个新的镜像
$ docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:版本
eg:docker commit -m="add vim " -a="techen" efrfsfd12 techen/myubunto:3.23

1、将本地镜像提交到阿里云镜像当中
登陆阿里云—> 管理控制台—〉 容器镜像服务 —>实例列表 —> 个人实例 —> 命名空间建命名、镜像仓库建立仓库
1. 登录阿里云Docker Registry
$ docker login --username=乾程吴彦祖 registry.cn-hangzhou.aliyuncs.com
用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。(bzq18107155240)
您可以在访问凭证页面修改凭证密码。
2. 从Registry中拉取镜像
$ docker pull registry.cn-hangzhou.aliyuncs.com/techen/superzqbo:[镜像版本号]
3. 将镜像推送到Registry
$ docker login --username=乾程吴彦祖 registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/techen/superzqbo:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/techen/superzqbo:[镜像版本号]
请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。
4. 选择合适的镜像仓库地址
从ECS推送镜像时,可以选择使用镜像仓库内网地址。推送速度将得到提升并且将不会损耗您的公网流量。
如果您使用的机器位于VPC网络,请使用 registry-vpc.cn-hangzhou.aliyuncs.com 作为Registry的域名登录。
5. 示例
使用"docker tag"命令重命名镜像,并将它通过专有网络地址推送至Registry。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
registry.aliyuncs.com/acs/agent 0.7-dfb6816 37bb9c63c8b2 7 days ago 37.89 MB
$ docker tag 37bb9c63c8b2 registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816
使用 "docker push" 命令将该镜像推送至远程。
$ docker push registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

2、将本地镜像推送到私服
在本地新建一个私有仓库供内部使用,Docker Registry是官方提供的工具,用于构建本地私有镜像仓库
# 拉取Docker Registry工具
$ docker pull registry
# 查看拉取Docker Registry工具是否成功
$ docker images
# 运行私有库Registry,相当于本地有一个Docker Hub;默认情况下会被容器会被创建在/var/lib/registry下
$ docker run -d -p 5000:5000 -v /home/techen/docker_registry/:tmp/registry --privileged=true registry
# 验证私服库上有什么镜像(相当于发送了一个Get请求)
$ curl -XGET http://ip:port/v2/_catalog
# 将新镜像改造成符合私服镜像的tag
$ docker tag 镜像:Tag IP:port/Repository:Tag
# 推送
$ docker push ip:port/镜像:版本
# 拉取
$ docker pull ip:port/镜像:版本
Docker默认不支持http方式推送镜像,要做如下处理

五、数据卷
Docker挂载主机目录访问出现:cannot open directory.:Permission denied
解决办法;在挂载后面加上 --privileged = true 参数即可
原理:Linux内部默认关掉了容器目录挂载的权限
数据卷主要的作用是映射(数据互相访问),完成容器内数据的持久化
# 运行一个带有数据卷的容器(如果目录不存在,会自动创建)
$ docker run -it --priviledged=true -v 宿主机目录:/容器目录 --name=容器起名 镜像名
# 运行一个带有数据卷的容器(如果目录不存在,会自动创建),容器可读可写(默认)
$ docker run -it --priviledged=true -v 宿主机目录:/容器目录:rv --name=容器起名 镜像名
# 运行一个带有数据卷的容器(如果目录不存在,会自动创建),容器可读不可写(容器内不能创建目录、编写文件)
$ docker run -it --priviledged=true -v 宿主机目录:/容器目录:ro --name=容器起名 镜像名
# 查看挂载信息(Mounts里面会有挂载信息)
$ docker inspect 容器id
数据卷的继承和共享
# 实现容器u1和u2之间的数据共享
$ docker run -it --priviledged=true --volumes-from 父类(容器名-u1) --name=u2 镜像名
六、DockerFile
1、DockerFile概念
DockerFile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本
DockerFile相当于是一个镜像文件,是可以正常打包运行的

2、DockerFile构建过程
DockerFile内容基础知识
1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下的顺序执行
3、#表示注解
4、每条指令都会创建一个新的镜像层,并对镜像层进行镜像提交
3、Docker执行DockerFile的大致流程
1、Docker从基础镜像运行一个容器
2、执行一条指令并对容器做出修改
3、执行类似docker commit的操作提交一个新的镜像层
4、docker基于刚刚提交的镜像运行一个新的容器
5、执行DockerFile当中的下一条指令,直到所有的指令都执行完毕

4、DockerFile保留字介绍
FROM:基础镜像,当前的新镜像是基于哪个镜像
MAINTAINER:镜像维护者的姓名和邮箱
RUN:容器构建是需要执行的指令,即build时就会执行DockerFile当中run里面的指令,一般有2种格式shell、exec格式(docker build时执行)
EXPOSE:当前容器对外暴漏的端口
WORKDIR:指定在创建容器后,终端默认登陆进来的目录,一个落脚点
USER:指令该镜像已什么样的用户去执行,默认root
ENV:设置环境变量,设置后后面可以使用
eg: ENV MY_PATH /usr/mytest
WORKDIR $MY_PATH
ADD:将宿主机目录下的文件拷贝进镜像,且会自动处理URL和解压tar压缩包(copy+解压)
COPY:类似ADD,将文件拷贝到镜像
VOLUME:数据卷
CMD:指定容器启动后要做的操作,DockerFile当中可以有多个CMD指令,但是只有最后一个会生效,CMD会被docker run之后的参数替换掉
CMD是在docker run的时候运行
RUN是在docker build的时候运行
ENTRYPOINT:也是用来指定一个**容器启动时要执行的指令**,类似于CMD,但是ENTRYPOINT不会被docker run之后的参数替换掉,而且这些命令行参数会被当中参数传递给ENTRYPOINT指定的程序
ENTRYPOINT["exec","parm1","parm2"]
ENTRYPOINT、CMD可以一起使用,一般变参会使用CMD,这里的CMD相当于给ENTRYPOINT传递参数
eg:
FROM nginx
ENTRYPOINT ["nginx","-c"] # 定参
CMD ["/etc/ngnix/nginx.conf"] #变参
------》 nginx -c /etc/ngnix/nginx.conf

5、构建DockerFile文件
1、编写
FROM java:8 # java8作为基础镜像
ENV PROJECT_HOME /home/project #设置环境变量,设置后后面可以使用
ENV FILE_NAME placeholder
ENV EXPOSE_PORT 8080
ENV ACTIVE_ENV dev
ENV JAVA_OPTS ""
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
RUN apk add --update ttf-dejavu fontconfig && rm -rf /var/cache/apk/*
RUN set -x && \
mkdir -p /root/logs/$FILE_NAME && \
mkdir -p $PROJECT_HOME
WORKDIR $PROJECT_HOME
ENTRYPOINT [ "/bin/sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar $PROJECT_HOME/$FILE_NAME.jar --spring.profiles.active=$ACTIVE_ENV" ]
EXPOSE $EXPOSE_PORT

2、构建
# 在dockerfile文件下执行下面的指令(注意tag后面有个空格和点)
$ docker build -t 新镜像的名字:TAG .
3、运行
docker run 镜像名
# 测试服务接口是否可用
$ curl 127.0.0.1:6001/order/test
七、Docker网络
docker安装之后会默认创建三个网络

# 创建网络
$ docker network create net1
# 删除网络
$ docker network rm net1
# 查看网络源数据
$ docker network inspect net1
1、容器之间的互联通信以及端口映射
2、容器Ip发生变化时,可以通过服务名直接调用


Docker容器内部的IP时有可能变化的,所以一般相互通信的服务要设置在同一个网段下面,新建一个网络,它的驱动模式是bridge。
八、Docker-compose
用来做容器管理的,相当于一次启动所有容器
Docker-compose使用的流程
1、编写DockerFile文件,定义各个微服务并构建成镜像
2、使用Docker-componse定义完整的业务单元
3、使用docker-compose up启动
常用指令
# 查看帮助
$ docker-compose -h
# 启动服务
$ docker-compose up
# 后台启动服务
$ docker-compose up -d
# 停止并删除所有容器、网络、卷、镜像
$ docker-compose down
# 进入容器内部
$ docker-compose exec yml里面服务的ID /bin/bash
# 展示所有当前docker-compose编排过且运行的容器
$ docker-compose ps
# 展示所有当前docker-compose编排过的容器的进程
$ docker-compose top
# 查看容器的输出日志
$ docker-compose logs yml里面服务的ID
# 检查配置(检查语法)
$ docker-compose config
# 检查配置,有问题才输出
$ docker-compose config -q
# 重启
$ docker-compose restart
# 关闭
$ docker-compose stop
# 开启
$ docker-compose start