基础篇
Docker简介
解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
开发/运维(DevOps)新一代开发工程师
docker官网:http://www.docker.com
Docker Hub官网: https://hub.docker.com/
容器与虚拟机比较
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
Docker安装
CentOS7安装Docker(官方步骤)
https://docs.docker.com/engine/install/centos/
- 卸载旧版本(官网)
- yum安装gcc相关
yum -y install gcc
yum -y install gcc-c++
- 安装需要的软件包
yum install -y yum-utils
- 设置stable镜像仓库(阿里云)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 更新yum软件包索引
yum makecache fast
- 安装DOCKER CE
yum -y install docker-ce docker-ce-cli containerd.io
- 启动docker
systemctl start docker
阿里云镜像加速
官网:https://promotion.aliyun.com/ntms/act/kubernetes.html
重启服务器
systemctl daemon-reload
systemctl restart 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 images
列出本地主机上的镜像
-a :列出本地所有的镜像(含历史映像层)
-q :只显示镜像ID。
docker search 镜像名字
–limit : 只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull 镜像名字[:TAG]
下载镜像
没有TAG就是最新版
docker system df 查看镜像/容器/数据卷所占的空间
docker rmi 镜像名字ID
删除镜像
-f 强制删除
删除多个 docker rmi -f 镜像名1:TAG 镜像名2:TAG
docker虚悬镜像
仓库名、标签都是的镜像,俗称虚悬镜像dangling image
容器命令
有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)
- 新建+启动容器
docker run [OPTIONS] image [COMMAND] [ARG...]
OPTIONS说明
- –name=“容器新名字” 为容器指定一个名称;
- -d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行)
- -i:以交互模式运行容器,通常与 -t 同时使用;
- -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
- -P: 随机端口映射,大写P
- -p: 指定端口映射,小写p
- 列出当前所有正在运行的容器
docker ps [OPTIONS]
OPTIONS说明
- -a :列出当前所有正在运行的容器+历史上运行过的
- -l :显示最近创建的容器。
- -n:显示最近n个创建的容器。
- -q :静默模式,只显示容器编号。
- 退出容器
exit
- run进去容器,exit退出,容器停止
ctrl+p+q
- run进去容器,ctrl+p+q退出,容器不停止
- 启动已停止运行的容器
docker start 容器ID或者容器名
- 重启容器
docker restart 容器ID或者容器名
- 停止容器
docker stop 容器ID或者容器名
- 强制停止容器
docker kill 容器ID或容器名
- 删除已停止的容器
docker rm -f 容器ID
-f 强制删除
- 重要,以redis为例
启动守护式容器(后台服务器)
- docker run -d redis:6.0.8
docker logs 容器ID
(查看容器日志)
docker top 容器ID
(查看容器内运行的进程)
docker inspect 容器ID
(查看容器内部细节)
进入正在运行的容器并以命令行交互
- docker exec -it 容器ID bashShell(推荐)
- exec 是在容器中打开新的终端,并且可以启动新的进程用exit退出,不会导致容器的停止。
- 重新进入docker attach 容器ID
- attach 直接进入容器启动命令的终端,不会启动新的进程用exit退出,会导致容器的停止。
docker cp 容器ID:容器内路径 目的主机路径(从容器内拷贝文件到主机上)
导入和导出容器
- export 导出容器的内容留作为一个tar归档文件[对应import命令]
- import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
- docker export 容器ID > 文件名.tar
- cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
常用命令
attach Attach to a running container # 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container’s filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值
Docker镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
Docker镜像层都是只读的,容器层是可写的当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
Docker镜像commit操作案例
docker commit提交容器副本使之成为一个新的镜像
docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]
本地镜像发布到阿里云
本地镜像发布到阿里云流程
创建仓库镜像
将镜像推送到阿里云
本地镜像发布到私有库
-
下载镜像Docker Registry
-
运行私有库Registry,相当于本地有个私有Docker hub
docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry
- 案例演示创建一个新镜像,ubuntu安装ifconfig命令
docker容器内执行上述两条命令:
apt-get update
apt-get install net-tools
公式:
docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]
命令:在容器外执行,记得
docker commit -m=“ifconfig cmd add” -a=“zzyy” a69d7c825c4f zzyyubuntu:1.2
- curl验证私服库上有什么镜像
curl -XGET http://192.168.111.162:5000/v2/_catalog
- 将新镜像zzyyubuntu:1.2修改符合私服规范的Tag
按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
自己host主机IP地址
使用命令 docker tag 将zzyyubuntu:1.2 这个镜像修改为192.168.111.162:5000/zzyyubuntu:1.2
docker tag zzyyubuntu:1.2 192.168.111.162:5000/zzyyubuntu:1.2
-
修改配置文件使之支持http
-
push推送到私服库
docker push 192.168.111.162:5000/zzyyubuntu:1.2
- curl验证私服库上有什么镜像2
curl -XGET http://192.168.111.162:5000/v2/_catalog
- pull到本地并运行
docker pull 192.168.111.162:5000/zzyyubuntu:1.2
docker run -it 镜像ID /bin/bash
Docker容器数据卷
容器数据卷是什么
将docker容器内的数据保存进宿主机的磁盘中
运行一个带有容器卷存储功能的容器实例:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
容器数据卷能干嘛
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。
为了能保存数据在docker中我们使用卷
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
数据卷案例
- 宿主vs容器之间映射添加容器卷
docker run -it --name myu3 --privileged=true -v /tmp/myHostData:/tmp/myDockerData ubuntu /bin/bash
docker inspect 容器ID
1 docker修改,主机同步获得
2 主机修改,docker同步获得
3 docker容器stop,主机修改,docker容器重启看数据是否同步。
- 读写规则映射添加说明
- 读写(默认)
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
默认同上案例,默认就是rw
- 只读
容器实例内部被限制,只能读取不能写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
- 卷的继承和共享
- 容器1完成和宿主机的映射
docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
- 容器2继承容器1的卷规则
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
Docker常规安装简介
总体步骤
搜索镜像
拉取镜像
查看镜像
启动镜像(服务端口映射)
停止容器
移除容器
安装tomcat
- docker pull tomcat
- docker images查看是否有拉取到的tomcat
- 使用tomcat镜像创建容器实例(也叫运行镜像)
docker run -it -p 8080:8080 tomcat
- 访问猫首页(把webapps.dist目录换成webapps)
- 免修改版说明
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
安装mysql
- docker pull mysql:5.7
- 使用mysql5.7镜像创建容器(也叫运行镜像)
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
docker ps
docker exec -it 容器ID /bin/bash
mysql -uroot -p
- 问题
docker上默认字符集编码隐患
SHOW VARIABLES LIKE ‘character%’
删除容器后,里面的mysql数据如何办
- 实战版mysql
- 新建mysql容器实例
docker run -d -p 3306:3306 --privileged=true -v /zzyyuse/mysql/log:/var/log/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(通过容器卷同步给mysql容器实例)
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
- 重新启动mysql容器实例再重新进入并查看字符编码
- 测试
安装redis
- docker pull redis:6.0.8
- 在CentOS宿主机下新建目录/app/redis
mkdir -p /app/redis
- 将一个redis.conf文件模板拷贝进/app/redis目录下
- /app/redis目录下修改redis.conf文件
- 使用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-cli连接上来第2次
高级篇
Docker复杂安装详说
安装mysql主从复制
- 新建主服务器容器实例3307
docker run -p 3307:3306 --name mysql-master
-v /zdz/mysql-master/log:/var/log/mysql
-v /zdz/mysql-master/data:/var/lib/mysql
-v /zdz/mysql-master/conf:/etc/mysql
-e MYSQL_ROOT_PASSWORD=root
-d mysql:5.7
- 进入/zdz/mysql-master/conf目录下新建my.cnf
[mysqld]
##设置server_id,同一局域网中需要唯一
server_id=101
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
##开启二进制日志功能
log-bin=mall-mysql-bin
##设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
##设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
##二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
##跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
##如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
- 修改完配置后重启master实例
docker restart mysql-master
- 进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -proot
- master容器实例内创建数据同步用户
CREATE USER ‘slave’@‘%’ IDENTIFIED BY ‘123456’;
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . TO ‘slave’@‘%’;
- 新建从服务器容器实例3308
docker run -p 3308:3306 --name mysql-slave
-v /zdz/mysql-slave/log:/var/log/mysql
-v /zdz/mysql-slave/data:/var/lib/mysql
-v /zdz/mysql-slave/conf:/etc/mysql
-e MYSQL_ROOT_PASSWORD=root
-d mysql:5.7
- 进入/zdz/mysql-slave/conf目录下新建my.cnf
[mysqld]
##设置server_id,同一局域网中需要唯一
server_id=102
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
##开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-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
- 修改完配置后重启slave实例
docker restart mysql-slave
- 在主数据库中查看主从同步状态
show master status
- 进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot
- 在从数据库中配置主从复制
change master to master_host=‘192.168.183.139’, master_user=‘slave’, master_password=‘123456’, master_port=3307, master_log_file=‘mall-mysql-bin.000001’, master_log_pos=617, master_connect_retry=30;
- 在从数据库中查看主从同步状态
show slave status \G;
- 在从数据库中开启主从同步
- 查看从数据库状态发现已经同步
- 注意!!!(字符编码)
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
安装Redis集群
3主3从redis集群配置
- 新建6个docker容器redis实例
docker run -d --name redis-node-1 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
命令分步解释:
–net host: 使用宿主机的IP和端口,默认
-v /data/redis/share/redis-node-6:/data: 容器卷,宿主机地址:docker内部地址
–cluster-enabled yes:开启redis集群
–appendonly yes:开启持久化
–port 6386:redis端口号
- 进入容器redis-node-1并为6台机器构建集群关系
docker exec -it redis-node-1 /bin/bash
进入docker容器后才能执行一下命令,且注意自己的真实IP地址
redis-cli --cluster create 192.168.183.139:6381 192.168.183.139:6382 192.168.183.139:6383 192.168.183.139:6384 192.168.183.139:6385 192.168.183.139:6386 --cluster-replicas 1
–cluster-replicas 1 表示为每个master创建一个slave节点
- 链接进入6381作为切入点,查看集群状态
主从容错切换迁移案例
数据读写存储
- 启动6机构成的集群并通过exec进入
- 对6381新增两个key
- 防止路由失效加参数-c并新增两个key
- 查看集群信息
redis-cli --cluster check 192.168.183.139:6381
容错切换迁移
- 主6381和从机切换,先停止主机6381
6381主机停了,对应的真实从机上位
6381作为1号主机分配的从机以实际情况为准,具体是几号机器就是几号
- 再次查看集群信息
- 先还原之前的3主3从
先启6381
docker start redis-node-1
再停6385
docker stop redis-node-5
再启6385
docker start redis-node-5
- 查看集群状态
主从扩容案例
- 新建6387、6388两个节点+新建后启动+查看是否8节点
docker run -d --name redis-node-7 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /zdz/redis-6cluster/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
- 进入6387容器实例内部
docker exec -it redis-node-7 /bin/bash
- 将新增的6387节点(空槽号)作为master节点加入原集群
将新增的6387作为master节点加入集群
redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:6381
6387 就是将要作为master新增节点
6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
- 检查集群情况第1次
redis-cli --cluster check 真实ip地址:6381
- 重新分派槽号
重新分派槽号
命令:redis-cli --cluster reshard IP地址:端口号
redis-cli --cluster reshard 192.168.183.139:6381
- 检查集群情况第2次
redis-cli --cluster check 真实ip地址:6381
- 为主节点6387分配从节点6388
命令:redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
redis-cli --cluster add-node 192.168.183.139:6388 192.168.183.139:6387 --cluster-slave --cluster-master-id e4781f644d4a4e4d4b4d107157b9ba8144631451-------这个是6387的编号,按照自己实际情况
- 检查集群情况第3次
redis-cli --cluster check 192.168.183.139:6382
主从缩容案例
- 目的:6387和6388下线
- 检查集群情况1获得6388的节点ID
redis-cli --cluster check 192.168.111.147:6382
- 将6388删除从集群中将4号从节点6388删除
命令:redis-cli --cluster del-node ip:从机端口 从机6388节点ID
redis-cli --cluster del-node 192.168.183.139:6388 f3219791956df1447965bf85e01281b3fa1c9cac
redis-cli --cluster check 192.168.183.139:6382
- 将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
redis-cli --cluster reshard 192.168.183.139:6381
- 检查集群情况第二次
redis-cli --cluster check 192.168.183.139:6381
4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了
- 将6387删除
命令:redis-cli --cluster del-node ip:端口 6387节点ID
redis-cli --cluster del-node 192.168.183.139:6387 e4781f644d4a4e4d4b4d107157b9ba8144631451
- 检查集群情况第三次
redis-cli --cluster check 192.168.183.139:6381
DockerFile解析
是什么
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run 镜像运行容器实例
DockerFile构建过程解析
- Dockerfile内容基础知识
1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层并对镜像进行提交
- Docker执行Dockerfile的大致流程
(1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
- 总结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
*Dockerfile是软件的原材料
*Docker镜像是软件的交付品
*Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2 Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
3 Docker容器,容器是直接提供服务的。
DockerFile常用保留字指令
- FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
- MAINTAINER
镜像维护者的姓名和邮箱地址
- RUN
容器构建时需要运行的命令
两种格式:
shell格式: RUN yum -y install vim
exec格式:
RUN是在 docker build时运行
- EXPOSE
当前容器对外暴露出的端口
- EXPOSE
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV
用来在构建镜像过程中设置环境变量
- ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
- COPY
类似ADD,拷贝文件和目录到镜像中。
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
COPY src dest
COPY [“src”, “dest”]
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
- VOLUME
容器数据卷,用于数据保存和持久化工作
- CMD
指定容器启动后的要干的事情
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
CMD是在docker run 时运行。
RUN是在 docker build时运行。
- ENTRYPOINT
也是用来指定一个容器启动时要运行的命令
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
- 总结
案例
自定义镜像mycentosjava8
Centos7镜像具备vim+ifconfig+jdk8
- 编写Dockerfile文件
FROM centos MAINTAINER zzyy<zzyybs@126.com> ENV MYPATH /usr/local WORKDIR $MYPATH #安装vim编辑器 RUN yum -y install vim #安装ifconfig命令查看网络IP RUN yum -y install net-tools #安装java8及lib库 RUN yum -y install glibc.i686 RUN mkdir /usr/local/java #ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置 ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/ #配置java环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_171 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 80 CMD echo $MYPATH CMD echo "success--------------ok" CMD /bin/bash
- 构建
docker build -t 新镜像名字:TAG .
- 构建
docker run -it 新镜像名字:TAG
微服务实战
- 通过IDEA新建一个普通微服务模块
2.通过dockerfile发布微服务部署到docker容器
- IDEA工具里面搞定微服务jar包
- 编写Dockerfile
# 基础镜像使用java FROM java:8 # 作者 MAINTAINER zdz # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为zdz_docker.jar ADD docker_boot-0.0.1-SNAPSHOT.jar zdz_docker.jar # 运行jar包 RUN bash -c 'touch /zdz_docker.jar' ENTRYPOINT ["java","-jar","/zdz_docker.jar"] #暴露6001端口作为微服务 EXPOSE 6001
将微服务jar包和Dockerfile文件上传到同一个目录下/mydocker
3. 构建镜像
docker build -t zdz_docker:1.6 .
4. 运行容器
docker run -d -p 6001:6001 --name springbootdemo zdz_docker:1.6
Docker网络
常用基本命令
- 查看网络
docker network ls
- 查看网络源数据
docker network inspect XXX网络名字
- 删除网络
docker network rm XXX网络名字
- All命令
能干嘛
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
网络模式
总体介绍
bridge模式:使用–network bridge指定,默认使用docker0
host模式:使用–network host指定
none模式:使用–network none指定
container模式:使用–network container:NAME或者容器ID指定
容器实例内默认网络IP生产规则
docker容器内部的ip是有可能会发生改变的
案例说明
- bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的
- host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
- none
在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo
需要我们自己为Docker容器添加网卡、配置IP等。
- container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
- 自定义网络
自定义桥接网络,自定义网络默认使用的是桥接网络bridge
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
Docker-compose容器编排
是什么
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
能干嘛
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
下载
curl -L “https://github.com/docker/compose/releases/download/1.29.2/docker-compose- ( u n a m e − s ) − (uname -s)- (uname−s)−(uname -m)” -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
Compose核心概念
- 一文件
docker-compose.yml
- 两要素
服务(service):
一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
工程(project):
由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
Compose编排微服务
- 编写docker-compose.yml文件
version: "3"
services:
microService:
image: zdz_docker:1.3
container_name: springbootdemo
ports:
- "6001:6001"
volumes:
- /doker-v/springbootdemo:/data
networks:
- zdz_net
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /docker-v/redis/redis.conf:/etc/redis/redis.conf
- /docker-v/redis/data:/data
networks:
- zdz_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'zdz'
MYSQL_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- /docker-v/mysql/db:/var/lib/mysql
- /docker-v/mysql/conf/my.cnf:/etc/my.cnf
- /docker-v/mysql/init:/docker-entrypoint-initdb.d
networks:
- zdz_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
zdz_net:
- 改造升级微服务工程docker_boot
spring.datasource.url=jdbc:mysql://mysql:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.redis.host=redis
- 执行 docker-compose up或者执行 docker-compose up -d
- 进入mysql容器实例并新建库db2021+新建表t_user
CREATE TABLE `t_user` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
- 测试
Docker轻量级可视化工具Portainer
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
安装
docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
设置admin用户和密码后首次登陆
选择local选项卡后本地docker详细信息展示
Docker容器监控之CAdvisor+InfluxDB+Granfana
原生命令
操作
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。。。。
但是,
docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
是什么
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
- CAdvisor
- InfluxDB
- Granfana
compose容器编排,一套带走
- 新建目录
- 新建3件套组合的docker-compose.yml
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
- 启动docker-compose文件
docker-compose up
- 测试
- 浏览cAdvisor收集服务,http://ip:8080/
- 浏览influxdb存储服务,http://ip:8083/
- 浏览grafana展现服务,http://ip:3000
ip+3000端口的方式访问,默认帐户密码(admin/admin)
配置步骤
- 配置数据源
- 选择influxdb数据源
- 配置细节
- 配置面板panel