文章开端先感谢尚硅谷无私的开源精神
- Docker 出现的原因:
单机版本中开发、运维环境依赖版本不一致。
集群环境中相比单机安装工作量增多、一不小心更容易错。
Docker 可以轻松实现系统平滑移植,容器虚拟技术。
开发人员可以借助Docker 消除写作编码时“在我机器上可以正常工作”的问题。
镜像即应用:运行文档、配置环境、运行环境、运行依赖包、操作系统发行版本、内核。
Docker 打破过往的【程序即应用】的观念,投过镜像将作业系统核心除外,运行应用程式所需要的的系统环境,由下到上打包,达到应用程式跨平台间的无缝接轨运作。
Docker 理念
一次镜像、处处运行。
Docker 是什么
基于GO语言的云开源项目。
Docker的主要目标是"Build,Ship and Run Any App,Anywhere" , 也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP (可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行"。
将应用打包成镜像,通过镜像成为运行在Docker 镜像上的实例,而Docker在任何操作系统上都是一致的,这就是实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机器上就可以一键部署好,简化了操作。
解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
Docker 并非是一个通用的容器工具,它依赖于已存在并运行的Linux内河环境
Docker 实质上是在已经运行的Linux 下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的Linux主机。因此Docker 必须部署在Linux内核的系统上。如果其他系统想部署Docker就必须安装虚拟的Linux环境。
Docker和传统虚拟化方式的不同之处
传统虚拟化技术是虚拟出一套硬件后,在其上运行一套完成的操作系统,在该系统上再运行所需的应用进程。
容器内的进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统的虚拟机更轻便。
每个容器之间相互隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。
Docker 的基本组成
镜像:Image 只读模板,镜像用来创建Docker 容器,一个镜像可以创建很多容器。
容器:Container 是镜像创建的运行实例,容器是镜像运行时的实体,容器为镜像提供了一个标准的和隔离的运行环境,他可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。容器可以被看作简易版本的Linux和运行在其中的应用程序。
仓库:Repository集中存放镜像文件的场所,类似于Maven 仓库、github。
Docker 是一个Client-Server结构的系统,Docker守护进程运行在主机上,然后通过Socket连接,从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。容器:一个运行时环境,就是前面说到的集装箱。
Docker 运行的基本流程:
- 用户使用Docker Client 与Docker Daemon 建立通信,并通过请求给后者。
- Docker Daemon 作为Docker 架构中主体部分,首先提供Docker Server 的功能使其可以接受 Docker Client 的请求。
- Docker Engine 执行Docker内部的一系列工作,每一项工作都是以一个Job的形式存在。
- Job 的运行过程中,当需要容器镜像时,则从Docker Registry 中下载镜像(本地有则用本地的),并通过镜像管理驱动graph Driver 将下载的镜像以Graph的形式存储。
- 当需要为Docker创建网络环境时,通过网络管理驱动Network Driver 创建并配置Docker容器网络环境。
- 当需要限制Docker容器运行资源或者执行用户指令等操作时,则通过Exec Driver 来完成。
- Libcontainer 是一项独立的容器管理包,Network Driver 以及Exec Driver 都是通过Libcontainer来实现具体对容器进行的操作。
Docker 安装
配置Docker 镜像加速地址
Docker 帮助启动类命令
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开机启动: systemctl enable docker
查看docker概要信息: docker info
查看docker总体帮助文档: docker --help
查看docker命令帮助文档: docker具体命令--help
Docker 镜像命令
docker images 列出本地主机上的镜像 -a 列出本地所有的镜像 -q 只显示镜像ID
docker search imageName 搜索镜像 --limit num imageName 分页查询
docker pull imageName:TAG 拉取镜像 不写TAG 相当于 docker pull imageName:latest
docker system df 查看镜像、容器、数据卷所占用的空间 -f 强制删除
docker rmi imageName|| imageId 根据镜像名称或者镜像ID删除
docker rmi -f 镜像名1:TAG 镜像名2:TAG 删除多个镜像
docker rmi-f $(docker images -qa) 删除全部镜像
docker ps -q -a | xargs docker rm 删除全部镜像
虚悬镜像(dangling image):仓库名、标签都是none的镜像
容器命令
- 新建+启动容器:docker run [option] image
--name=指定新名称
-d 后台运行容器并返回容器ID,也即启动守护式容器(后台运行)
-i 以交互模式运行容器,通常与-t同事使用;interactive
-t 为容器重新分配一个伪输入终端,通常与-i同时使用;tty
也即启动交互式容器(前台有伪终端,等待交互)
-P 随机端口映射
-p 指定端口映射 -p 8080:80 (宿主机端口:容器暴露端口)
示例:docker run -it centos /bin/bash
使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令,放在镜像名后的是命令,这里我们希望有个交互式Shell,因此用的是/bin/bash,要退出终端,直接输入exit。
- 列出正在运行的容器:docker ps [options]
-a 列出当前所有正在运行的容器+历史上运行过的
-l 显示最近创建的容器
-n 显示最近N个创建的容器
-q 静默模式,只显示容器编号
- 退出容器
exit run进去容器,exit退出,容器停止
ctrl+p+q run进去容器,ctrl+p+q退出,容器不停止
- 启动已经停止的容器 docker start containerId | imageName
- 停止已经启动的容器 docker stop containerId | imageName
- 强制停止已经启动的容器 docker kill containerId | imageName
- 删除已经停止的容器 docker rm containerId | imageName
- 启动守护式容器 后台运行 docker run -d imageName
这样运行会docker ps 查看不到运行的容器
docker 容器后台运行,就必须有一个前台进程
容器运行的命令如果不是那些一直挂起的命令(比如top tail),就是会自动退出。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如 service nginx start 但是,这样做nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀因为他觉得没事可做了。所以解决方案:将你要运行的程序以前台进程的形式运行,常见的就是命令行模式,表示我还有交互操作,别中断。
- 查看容器日志 docker logs containerId
- 查看容器内运行的进程 docker top containerId
- 查看容器内部细节 docker inspect containerId
- 进入容器并以命令行交互
docker exec -it containerId /bin/bash
docker attach containerId
二者区别:
attach 直接进入容器启动命令终端,不会启动新的进程,用exec直接退出,会导致容器停止。
exec 是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。
推荐使用exec。
- 容器内拷贝文件到主机
docker cp containerId:容器内路径 目标主机路径
- 导入和导出容器(容器的备份与恢复)
export 导出容器的内容流作为一个tar归档文件【对应import命令】
import 从tar包中的内容床架你一个新的文件系统再导入为镜像【对应exort】
docker exort containerId > 文件名.tar
cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号
Docker 镜像
镜像时分层的。
UnionFS 联合文件系统:Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层一层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。Union 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像,可以制作各种具体的镜像。特性:以此同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker 像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上,包含的就是典型Linux系统中的/dev, /proc, /bin, letc等标准目录和文件。rootfs就是 科不同的操作系统发行版,比如Ubuntu, Centos等等。
对于一个精简的os, rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel, 自己只需要提供rootfs就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别,因此不同的发行版可以公用bootfs。
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。1比如说有多个镜像都从相同的base 像构建而来,那么Docker Host只需在磁盘上保存一份base锐像;同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
重点理解:Docker镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部,这一层通常被称作容器层,容器层之下都叫做镜像层。
Docker commit命令 生成新镜像
docker commit 提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:【标签名】
发布镜像至阿里云镜像库
略略略
发布至私有镜像库
Docker Registry
docker run-d -p 5000:5000 -v /zzyyuse/myregistryl:/tmp/registry --privileged=true registry
- docker 容器内执行下面的命令:
apt-get update
apt-get install net-tools
- 容器外执行产生新镜像
docker commit -m="提交的描述信息" -a"=作者" 容器ID 要创建的目标镜像名[标签名]
- 验证私服库是否存在镜像
CURL-XGET http:192.168.162:5000/v2/_catalog
- 将新镜像放入私服库
按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
示例:Docker tag zzyyubuntu:1.2 192.168.111.162:5000/zzyyubuntu:1.2
- 修改配置文件使之支持HTTP
cat /etc/docker/daemon. json
添加:"insecure-registries": ["192.168.111.162:5000"]
重启Docker
- 推送镜像到私服库
docker push 192. 168. 111. 167: 5000/zzyyubuntu: 1. 2
- 拉取私有库的镜像
docker pull 192. 168. 111. 167: 5000/zzyyubuntu: 1. 2
容器数据卷 -v 宿主机的路径:容器内的路径(方便文件备份)
避坑:Docker挂载主机目录访问如果出现 cannot open directory . : Permission denied
解决办法:挂载目录后多加一个参数 --privileged=true
原因:如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用-privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数, container内的root拥有真正的root权限,否则, container内的root只是外部的,个普通用户权限。
容器数据卷有点类似于redis的rdb和aof文件完成容器内数据的持久化并备份到本地主机目录。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System 提供一些用于持续存储或共享数据的特性。
卷的设计就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
Docker 容器产生的数据如果不备份,那么当容器示例删除后,容器内的数据自然也就没有了,为了保存数据在Docker中我们使用卷。并实现双向读写。
特点:
- 数据卷可以再容器之间共享或重用数据
- 卷的更改可以直接实时生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
- 查看容器卷是否挂在成功 docker inspect containerId
Mouns节点下面的 Source 和 Destination 可以确定容器卷绑定的源和目标路径
- docker修改,主机同步获得
- 主机修改. docker同步获得
- docker容器stop 主机修改 docker容器重启查看数据是否同步 ?答案:是
- 读写规则和规则说明
容器内部只读权限:容器实例内部被限制,只能读取不能写
docker run -it --privileged=true -v/宿主机绝对路径:/容器内目录:ro 镜像名
- 卷的继承和共享(继承的是父容器的规则,而不是卷文件)
docker run -it -privileged=true --volumes-from 父类容器别名 --name u2 imageName
docker 上软件安装
运行容器即可,注意参数。。。
docker pull image
docker run image
示例:简单安装mysql 可能遇到的问题:1、插入中文、可能报错;2、删除容器,数据也不复存在。
查看字符集编码 show variables like 'character%'
#提高数据安全性;解决删除容器,数据文件也被删除的问题---挂载数据卷 日志、数据、配置文件
docker run -d -p 3306:3306 --privileged=true
-v /zzyyuse/mysql/log:/var/1og/mysql
-v /zzyyuse/mysql/data:/var/lib/mysql
-v /zzyyuse/mysql/conf:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456
--name mysql mysql:5.7
#解决插入中文乱码问题---进入宿主机配置文件目录,创建my.cnf
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_genera_ci
character_set_server = utf8
#重启mysql,之后新建的DB有效,需要重新建立DB
结论:docker 安装完成mysql 并run出容器后,建议请先修改完成字符集编码后再新建mysql数据库-表-插入数据
示例安装Redis
- 从docker hub上(阿里云加速器)拉取redis镜像到本地标签为6.0.8
- 入门命令
- 命令提醒:容器卷记得加入--privileged=true
- 在Centos宿主机下新建目录/app/redis mkdir -p/app/redis
- 将一个redis.conf文件模板拷贝进/app/redis目录下 cp /myredis/redis.conf /app/redis
- /app/redis目录下修改redis.conf文件 默认出厂的原始 redis.conf
允许redis外地链接:注释掉#bind 127.0.0.1
关闭redis后台进程: 注释掉 #daemonize yes 或者设置 daemonize no ;该配置和docker run 中 -d 参数冲突,会导致容器一直启动失败
- 使用redis6. 0.8镜像创建容器(也叫运行镜像)
docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf #设置指定的文件
- 测试redis-cli连接上来
- 请证明docker启动使用了我们自己指定的配置文件
redis默认的数据库为16个,修改redis 数据库数来验证 select 10
- 测试redis-cli连接上来第2次
Docker 高级篇
- docker 中 mysql 主从复制
1.新建主服务器容器实例3307
docker run -p 3307:3306
--name mysq-master
-v /mydata/mysql-masterlog:/varlog/mysql
-v /mydata/mysql-master/data:/varlib/mysql
-v /mydata/mysal-master/conf:/etc/mysql
-e MYSQL_ROOT_PASSWORD=root
-d mysql:5.7
2.进入/mydata/mysql-master/conf目录下新建my.cnf
[mysqld]
##设置server-id,同一局域网中需要唯一
server_id-101
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
#开启二进制日志功能
log-bin=mall-mysql-bin1
##设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
##设置使用的二进制日志格式(mixed, statement, row)
binlog_format=mixed
##二进制日志过期清理时间,默认值为0:表示不自动清理。
expire_logs_days=7
##跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
##如: 1062错误是指一些主键重复, 1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
3.修改完配置后重启master实例
docker restart mysql-master
4.进入mysql-master容器
docker exec -it mysql-master /bin/bash
5.master容器实例内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456;
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* To 'slave'@%;
6.新建从服务器容器实例3308
docker run -p 3308:3306
--name mysq-master
-v /mydata/mysql-slave/log:/varlog/mysql
-v /mydata/mysql-slave/data:/varlib/mysql
-v /mydata/mysal-slave/conf:/etc/mysql
-e MYSQL_ROOT_PASSWORD=root
-d mysql:5.7
7.进入/mydata/mysql-slave/conf目录下新建my.cnf
[mysqld]
##设置server-id,同一局域网中需要唯一
server_id=102
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
#开启二进制日志功能,以备salve作为其他数据库实例的master时使用
log-bin=mall-mysql-slave-bin
##设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
##设置使用的二进制日志格式(mixed, statement, row)
binlog_format=mixed
##二进制日志过期清理时间,默认值为0:表示不自动清理。
expire_logs_days=7
##跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
##如: 1062错误是指一些主键重复, 1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
##relay-log配置中继日志
relay_log=mall-mysql-relay-bin
##log-slave-updates表示slave将复制事件写进自己的二进制日志
log_slave_updates-1
##slave设置为只读(具有super权限的用户除外)
read_only=1
8.修改完配置后重启slave实例
docker restart mysql-slave /bin/bash
9.在主数据库中查看主从同步状态
show master status
10.进入mysal-slave容器
docker exec -it mysql-slave
11.在从数据库中配置主从复制
change master to master-host='宿主机ip', master_user='slave', master-password='123456', master_port=3307, master_log_file='mall-mysal-bin.000001', master_log_pos=617,master_connect_retry=30;
master-host:主数据库的IP地址;
master_port:主数据库的运行端口;
masteruser:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件 通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect retry:连接失败重试的时间问隔,单位为秒。
12.在从数据库中查看主从同步状态
show slave status \G
主要看
Slave IO Running: No
Slave SOL Running: No
13.在从数据库中开启主从同步
start slave
14.查看从数据库状态发现已经同步
show slave status \G
Slave IO Running: YES
Slave SOL Running: YES
15.主从复制测试
主数据库创建数据库-数据表-插入数据
从数据库查看数据
Redis大厂面试
- Hash 取余进行分区
2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机。假设有N台机器构成一个集群,用户每次读写操作都是根据公式hash(key) %N器E数,计算出哈希值,用来决定数据映射到哪一个节点上。
优点:简单粗暴,直接有效, 只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息) ,起到负载均衡+分而治之的作用。
缺点:原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化: Hash(key)/3会变成Hash(key)/7,此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌 。
- 一致性Hash算法
一致性Hash算法背景:一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。
算法构建一致性Hash环
服务器IP节点映射
key落到服务器的落键规则
优点:
缺点:
小结:
- 哈希槽分区
Hash 槽的计算
Docker 上Redis 3主3从案例
docker run
-d
--name redis-node-6 容器名字
--net host 使用宿主机的ip和端口,默认
--privileged=true 获取宿主机root用户权限
-v /data/redis/share/redis-node-1:/data redis:6.0.8 容器卷,宿主机地址:docker内部地址
--cluster-enabled yes 开启redis集群
--appendonly yes #开启持久化
--port 6381 #redis 端口号
修改 --name redis-node-1 至 redis-node-6
--port 6381 至 6386
执行6次 创建并启动 6个redis容器
进入随意一个redis容器执行命令
redis-cli--cluster create 192.168.111.147:6381 192.168.111.147:6382 192.168.111.147:6383 192.168.111.147:6384 192.168.111.147:6385 192.168.111.147:6386 --cluster-replicas 1
--cluster-replicas 1 #表示master创建一个slave节点 主动分配 1对1 谁挂载谁的后面自己决定
以上代码执行成功之后见下图结果
- 进入一个redis容器查看集群状态 redis-cli -p 6381
cluster info
cluster nodes
集群建立之后不能使用单机版命令进入集群,这样会发生存取错误、输出路由跳转异常信息、这是因为集群种存在槽位的问题。为了防止路由失效需要添加-c参数进入集群环境。
redis-cli -p 6381 -c
redis-cli --cluster check ip:host
- 主从容错切换迁移
redis主机停掉,从机主动上位变为主机。
主机停掉之后、从机主动上位变为主机,原主机启动之后、会变为新的从机。
- 主从扩容
需求:3主3从变为4主4从
1.新建6387,6388两个节点+新建后启动+查看是否8节点
2.进入6387容器实例内部 docker exec-it redis-node-7/bin/bash
3.将新增的6387节点(空槽号)作为master节点加入原集群
redis-cli --cluster add-node ip:6387 ip:6381
#6387就是将要作为master新增节点6381就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
4.检查集群情况第1次
redis-cli --cluster check ip:6381
此时可以看出没有槽位
5.重新分派槽号
redis-cli --cluster reshard ip:6381
6.检查集群情况第2次
redis-cli --cluster reshard ip:6381
每个原来的主机把槽位分别分给新的主机
slots: [0-1364] [5461-6826] [ 10923-12287] (4096 slots) master
7.为主节点6387分配从节点6388
redis-cli --cluster add-node 192.168.111.167:6388 192.168.111.167:6387 --cluster-slave --cluster-master-id e4781f644d4a4e4d4b4d107157b9ba8144631451-----这个是6387的编号,按照自己实际情况
8.检查集群情况第3次
- 主从缩容
需求:4主4从变为3主3从,先删从节点
1.目的: 6387和6388下线
2.检查集群情况 获得6388的节点ID
redis-cli --cluster check ip:host
3.将6388删除从集群中将4号从节点6388删除
redis-cli --cluster del-node ip:从机端口 从机ID
4.将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
redis-cli --cluster reshard ip:6381
5.检查集群情况第二次
redis-cli --cluster check ip:host
6.将6387删除
redis-cli --cluster del-node ip:端口 删除容器id
7.检查集群情况第三次中
redic-cli -- cluster check ip:host
Docker File
DockerFile 是构建Docker镜像的文本文件,是由一条条构建颈线IG所需的指令和参数构成的脚本。
- 每条保留字指令都必须大写字母且后面要跟随至少一个参数
- 每条指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
Docker 执行DockerFile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit 的操作提交一个新的镜像层
- docker 再基于刚提交的镜像运行一个新容器
- 执行DockerFile中的下一条指令直到所有指令都执行完成
保留字指令
- FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条是from
- MAINTAINER 镜像维护者的姓名和邮箱地址
- RUN 容器构建时需要运行的命令,有两种格式,shell 格式 exec 格式,RUN 是在docker build 时运行
RUN <命令行命令> #<命令行命令>等同于,在终端操作的shell命令
RUN ["可执行文件",“参数一”,“参数二”] 例如:["./test.php","dev","offline"] 等价于RUN ./test.php dev offline
- EXPOSE 当前容器对外暴露的端口
- WORKDIR 指定创建容器后,终端登录容器进入的目录,一个落脚点
- USER 指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV 用来构建镜像过程中设置环境变量
- ADD 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
- COPY 类似于ADD,拷贝文件和目录到镜像中。将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置 COPY src dest | COPY["src","dest"]
- VOLUME 容器数据卷 ,用于数据保存和持久化工作
- CMD 指定容器启动后要干的事情 注意:DockerFile 中可以有多个CMD指令,但只有最后一个生效。CMD会被docker run 之后的参数替换。即启动镜像的时候 docker run ...... 参数替换。它和前面RUN的区别:CMD 是在docker run 时运行 。RUN 是在 docker build 时运行。
- ENTRYPOINT 也是用来指定一个容器启动时要运行的命令,类似于CMD指令,但是 ENTRYPOINT 不会被docker run 后面的指令覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINT 指令指定的程序
- 构建DockerFile
docker build -t 新镜像名字:TAG .
- 虚悬镜像
删除:docker image prune
- docker运行微服务
编写Dockerfile
构建镜像
docker build -t imageName:imageTag
运行镜像
docker run -d -p 宿主机host:容器host imageId