0X1 简介
0X1.1 Why docker?
在开发和运维部署的流程中,可能存在开发和运维的环境配置不相同的情况
导致我们的SRC源代码run不起来而产生矛盾
而docker的出现很好的解决了这一问题,docker可以把整个环境打包形成一个镜像文件,原封不动的照搬过来,这样就100%不会有冲突
0X1.2 docker设计理念
Docker是go语言的开源项目,docker可以做到‘一次镜像,处处运行’的效果。
是解决了运行环境和配置问题的软件容器
0X1.3 传统虚拟机和docker的对比
- The shortcomings of VM
资源占用多,步骤多,启动慢
- The advantages of docker container
可以复用,启动快速,占用内存少
0X1.4 docker的构成
镜像,容器,仓库是构成docker的三大部分
- 镜像
可以理解为类与对象,new classs()
类就相当于镜像文件
容器
镜像创造出来的容器,一个对象可以创造很多个容器
类与对象中,实例对象就相当于容器
- 仓库
集中存放镜像文件的地方
类似于:
github仓库,存放各种git项目的地方
docker公司提供的官方registry被称为docker hub,存放各种镜像模板的地方
仓库分为私有仓库和公开仓库,dockerhub是最大的公开仓库
0X1.5 Install docker
真是出省啊,为什么每次kali虚拟机就会出现一大堆B毛病我草!!!!!
永远不要用deb包去安装,会变得不幸,想安装好就老老实实的看这里:![7%YIJXOM]01DK}H5OE7925.jpg](https://cdn.nlark.com/yuque/0/2022/jpeg/32634994/1663300754775-ed741ec0-7941-4b4d-8ced-65016b8ee664.jpeg#averageHue=%23a9aaa6&clientId=u15e908d6-7be0-4&from=paste&height=208&id=ue9ad9b76&name=7%25YIJXOM%5D01DK%7DH5OE7925.jpg&originHeight=260&originWidth=278&originalType=binary&ratio=1&rotation=0&showTitle=false&size=17832&status=done&style=none&taskId=u1ccd1f29-9a65-4209-a584-37ebdeafb93&title=&width=222.4)
1 | #新重写sources.list中内容,一个个字母删除太久了 |
1 | #其他apt源 |
更新系统工具:apt-get update && apt-get upgrade && apt-get dist-upgrade
清除缓存:apt-get clean
采用apt安装docker:
为什么采用apt安装?因为之后采用apt源安装Docker的其他组件时,新组件与已安装的Docker容器最为匹配。apt-get install docker docker-compose
或apt-get install docker.io
检测docker是否安装成功:
1 | #启动docker服务 |
妈的这上面的步骤一步也别乱,真的
0X1.6 docker镜像加速器配置
配置镜像加速器:
先去阿里云注册一个账号,点击镜像工具:
将这段代码在命令行运行
1 | sudo mkdir -p /etc/docker |
sudo systemctl daemon-reload
sudo systemctl restart docker
这样就完成了镜像加速的配置
运行完后,输入docker info
如果有这一段信息就说明成功了:
划掉的部分就是阿里云里的地址
最后再设置一个开机自启systemctl enable docker
这样每次开机就不需要手动开启了
1X1 Docker 命令
1X1.1 启动类
启动docker:systemctl start docker
停止docker:systemctl stop docker
重启docker: systemctl restart docker
查看docker状态:systemctl status docker
开机自启动:system enable docker
查看docker概要信息:docker info
查看docker帮助文档:docker --help
查看docker命令帮助文档:docker 具体命令 --help
1X1.2 镜像命令
- 列出本地主机上的镜像文件:
docker images
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:创建时间
SIZE:内存大小
[OPTION]:
-a:列出本地所有镜像(包括历史镜像层)
-q:只显示镜像id
- 查找某个镜像:
docker search 镜像
:
在远程库里找镜像
NAME:名称
DESCRIPTION:说明
STARS:点赞数
OFFICIAL:是否为官方的
AUTOMATED:是否为自动构建的
NAME中的前缀就是作者的名字,包名
[OPTION]:
–limit:只列出N个镜像,默认25个docker search --limit 5 redis
- 拉取镜像:
docker pull 镜像
其中镜像的名称有2套写法:docker pull 镜像名字:latest
下载最新版docker pull 镜像名字
下载指定版本
- 查看镜像/容器/数据卷所占的空间
docker system df
删除某个镜像
docker rmi xxxx
docker rmi -f $(docker images -aq)
:删除全部
[OPTION]:
-f 强制删除
1X1.3 Ubuntu 容器例子
首先先拉一个ubuntu的镜像:
1X1.3.1 生成容器
docker run [option]IMAGE[command][arg]
[OPTION]:docker run -it ubuntu /bin/bash
:
以交互模式启动一个Ubuntu容器,在容器内执行/bin/bash命令,也就是shell命令
docker ps[OPTION]
docker run -it --name=kino ubuntu bash
:
以交互模式启动一个名称是kino的Ubuntu容器,在容器内执行/bin/bash命令
1X1.3.2 退出容器
exit
或者CTRL+D
:run进容器,exit退出,容器停止ctrl+p+q
:run进容器,但是容器不停止
1X1.3.3 进入停止的容器和启动着的容器
如果我们是ctrl+p+q退出的,我们想要再次进入只需要docker attach 容器ID或者名字
如果我们是exit或者ctrl+d退出的:docker strat 容器ID或者名字
再运行docker attach 容器ID或者名字
即可
还有一种方法,更加细,可以指定模式:docker exec 选项 容器 指令
:如docker exec -it kino /bin/bash
这样就可以重新进入容器
attach和exec的区别:
1X1.3.4 重启,停止,强制停止,删除容器
重启容器:docker restart 容器ID/name
停止容器:docker stop 容器ID/name
强制停止容器:docker kill 容器id/name
删除已停止的容器:docker rm 容器ID/name
,docker rmi是删除镜像,别搞混了docker rm -f 容器
:强制删除
一次性删除多个容器:docker rm -f $(docker ps -aq)
或者docker ps -aq|xargs docker rm
,xargs做题时见到过
1X1.3.5 重要指令
docker run -d
:后台跑一个容器,如果跑的是Ubuntu就不会成功,准确的说是一旦启动就会停止,因为Ubuntu是一个操作系统不是一个后台程序
以redis来演示前后台区别:
- 前台交互式运行:
docker run -it --name=boogipop redis
这样子启动的话一旦ctrl+c不小心退出了就没了:
可以看到的redis已经停止运行了
- 后台模式
docker run -d --name=boogipop redis
:后台启动,也就是守护式启动
查看容器日志:docker logs 容器
查看容器内进程:docker top 容器
查看容器运行细节:docker inspect 容器
呈现出来的是一种docker的形式
从容器内拷贝文件到主机中:docker cp 容器ID:容器内路径 目标主机路径
如把Ubuntu的tmp目录下的1.txt复制到主机的/opt下:docker cp kino:/tmp/1.txt /opt
导入和导出容器:export
:导出容器的内容流作为一个tar归档文件【对应import
命令】import
:从tar包中的内容创建一个新文件系统,再导入为镜像【对应export
】
如,把我的Ubuntu导出:docker export kino > /opt/ubuntu.tar
再删除我们docker的Ubuntu容器,然后导入:cat 文件名.tar|docker import- 镜像用户/镜像名:版本号
cat /opt/ubuntu.tar|docker import - boogipop/ubuntu:latest
可以看到文件还在里面
2X1 镜像层的观念
镜像分层概念
以pull指令为例,在下载的过程中docker的镜像好像是一层层的下载:
3X1 Commit 命令
先进入Ubuntu容器中运行apt-get update
再安装vim,apt-get -y install vim
这样就可以使用vim指令了
3X1.1 Commit制作镜像
docker commit
:提交容器副本使之成为一个新镜像docker commit -m="需要提交的信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
docker commit -m="add vim ok" -a="yyl" kino myubuntu
随后可以再images中看到我们的myubnutu
3X1.2 image上传阿里云
阿里云创建命名空间:
在镜像仓库中创建一个新仓库:
这里有很多命令我们直接复制就可以:
将本地镜像推送至阿里云:docker login --username=b0ogipopregistry.cn-hangzhou.aliyuncs.com
这里的登入密码在个人实例->访问凭证设置
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/imaginator/myubuntu:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/imaginator/myubuntu:[镜像版本号]
这样就发布到了阿里云上面
从registry里拉取镜像:docker pull registry.cn-hangzhou.aliyuncs.com/imaginator/myubuntu:[镜像版本号]
3X1.3 docker私有库
首先先下载registry:docker pull registry
:
运行私有库registry相当于本地有个私有docker hub
docker run -d -p 5000:5000 -v /b0ogipop/myregistry/:/tmp/registry --privileged=true registry
进入我们安装了vim的Ubuntu容器:
先apt-get update
在apt-get install net-tools
安装完后就可以使用ifconfig命令
再commit打包:docker commit -m="add net ok" -a="yyl" kino myubuntu:2.0
curl验证私服上有什么镜像:curl -XGET http://117.21.100.128:5000/v2/_catalog
发现没有
将tag改为符合标准的:docker tag 镜像:tag Host:port/repository:tag
docker tag myubuntu:2.0 117.21.100.128:5000/myubuntu:2.0
修改配置文件使之支持http:cat /etc/docker/daemon.json
docker默认不允许http方式推送镜像,通过配置选项来取消这个限制
推送我们的镜像到本地私服库:docker push 镜像名
docker push 117.21.100.128:5000/myubuntu:2.0
curl验证私服库有什么镜像:curl -XGET http://117.21.100.128:5000/v2/_catalog
上传成功
pull到本地运行:docker pull 117.21.100.128:5000/myubuntu:2.0
4X1 容器卷
一个坑:
冒号左边的是宿主机的文件地址,右边的是容器地址
是什么:
容器数据在主机的备份文件
运行一个带有容器卷储存功能的容器:docker run -it --privileged=true -v 宿主机绝对路径:容器内目录 镜像名
4X1.1 容器卷和主机互通互联
docker run -it --privleged=true -v /tmp/myhostdata:/tmp/myhostdata myubuntu /bin/bash
在docker容器里的/tmp/myhostdata写上一个1.txt:
退出容器去主机的/tmp/myhostdata去看看
看到没,实时同步加载文件,互相同步
主机写的文件容器内也会有,容器内写的主机也会有,互通互联
查看数据卷是否挂载成功:docker inspect 容器ID
,这里查看刚刚建的容器
这里看到有挂载,成功了
当我们的容器停止时,在主机内/tmp/myhostdata里面写入文件,在start容器,发现依旧同步过去了
4X1.2 容器卷ro和rw读写规则
只需要加一个:ro就可以实现只读权限
这时候容器内只可以读
4X1.3 容器卷之间的继承
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
继承父类容器卷
上面的-v全名就是-volumes
5X1 docker上安装软件说明
总体步骤:搜索->拉取->查看->启动镜像->停止容器->移除容器
5X1.1 安装tomcat
docker search tomcat
docker pull tomcat
,默认不加版本号安装最新版docker images
即可安装成功
docker run -it --name=tomacat1 -p 8080:8080 tomcat
-p:指定端口映射
-P:
在tomcat的虚拟终端可以看到,webapps文件夹下什么都没有,所以我们访问不到tomcat服务器
rm -r webapps
删掉webapps
真正的内容在webapps.dist里,我们把他重命名一下
这是最新版的tomcat的毛病
出来了tomcat
5X1.2 安装MYSQL
docker pull mysql:5.7
安装一个mysql5.7
如何启动一个mysql容器:docker run --name 容器名字 -e MYSQL_ROOT_PASSWORD=ROOT密码 -d mysql:版本号
-e是环境的意思docker run --name mysql1 -e -p 3306:3306 MYSQL_ROOT_PASSWORD=root -d mysql:5.7
运行成功
假如你linux主机有mysql启动,那docker里的3306端口就会被占用
docker exec -it mysql1 /bin/bash
进入容器mysql -uroot -p
:
登入mysql
成功登入mysql
可以执行指令
建一个库再建一个表:create database db1;
创建数据库db1create table t1(id int,name varchar(20));
在数据库建立表t1insert into t1 values(1,'kino');
往表里插入数据
用SQLYOG连接:
5X1.3 MYSQL2(高级版)
docker run -d -p 3306:3306 --privileged=true -v /boogipop/mysql/log:/var/log/mysql -v /boogipop/mysql/data:/var/lib/mysql -v /boogipop/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7
修改配置文件:cd /boogipop/mysql/conf
新建一个文件my.cnf
:
1 | [client] |
这就解决中文乱码
5X1.4 安装redis
docker pull redis
mkdir -p /app/redis
cp /myredis/redis.conf/app/redis/
把宿主机的redis配置文件复制一份过来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 redis server /etc/redis/redis.conf
运行一个带可以和主机交互的容器卷的容器docker exec -it myr3 /bin/bash
redis-cli
set k1 v1
get k1
6X1 Redis+Mysql–docker
6X1.1 MYSQL主从复制docker版
docker run -d -p 3307:3306 --privileged=true -v /boogipop/mysql/log:/var/log/mysql -v /boogipop/mysql/data:/var/lib/mysql -v /boogipop/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7
先run一个主机
配置主机的配置conf:
1 | [mysqld] |
CREATE USER 'slvae'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
创建一个slave用户,并赋予权限
docker run -d -p 3308:3306 --privileged=true -v /mysql-slave/mysql/log:/var/log/mysql -v /mysql-slave/mysql/data:/var/lib/mysql -v /mysql-slave/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysql-slave mysql:5.7
创建从服务器
配置从服务器的conf文件:
1 | [mysqld] |
重启slave和mysql容器实例:docker restart mysql
docker restart mysql-slave
在主服务器查看主从状态:show master status;
再进入从服务器:docker exec -it mysql-slave /bin/bash
主从赋值参数说明:
1 | master_host:主数据库的IP地址; |
所以我们输入change master to master_host='117.21.100.128',master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=154,master_connect_retry=30;
在从服务器中查看主从同步状态:show slave status \G;
-G是以竖着的方式列出
这里两个NO说明还未开始
在从数据库中开启主从状态:start slave;
可以发现已经开起来了
主从服务测试:
接下来主服务器建立数据表
从服务器查看:
显示出来了,说明成功
6X1.2 分布式存储之哈希取余算法
能干嘛:
三大步骤:
一致性哈希环:
节点映射:
优点:
容错性
拓展性
缺点:
6X1.3 分布式储存之哈希槽算法
为什么用16384个槽:
是什么:
6X1.4 3主3从redis集群配置
关闭防火墙+启动docker服务:systemctl stop firewalld
systemctl start docker
新建6个redis容器实例:docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis --cluster-enabled yes --appendonly yes --port 6386
一口气直接嗦,创建6台容器实例
–net host:使用宿主机的IP和端口,默认
–privilege=true:获取宿主机root用户权限
-v /data/redis/share/redis-node-1:/data:容器卷,宿主机地址:docker内部地址
–cluster-enabled yes:开启redis集群
–appendonly yes:开启持久化
–port 6386:redis端口
进入redis-node-1并且为6台机器构建集群关系:
进入容器docker exec -it redis-node-1 /bin/bash
构建集群redis-cli --cluster create 117.21.100.128:6381 117.21.100.128:6382 117.21.100.128:6383 117.21.100.128:6384 117.21.100.128:6385 117.21.100.128:6386 --cluster-replicas 1
–cluster-replicas:表示为每个master创建一个slave节点
performing hash slots allocation on 6 nodes:表示创建哈希槽
下面有3台主服务器的槽点位置0-5460,5461-10922,10923-16383
接下来按照提示输入yes即可
6381,6382,6383是三台主机
6384,6385,6386是三台从机
以6381为切入点,查看节点状态:redis-cli -p 6381
cluster info
查看集群状态cluster nodes
查看主从服务器
根据这里可以看到,配对方式是,6381-6386,6382-6384,6383-6385
主从关系是随机分配
6x1.4.1主从容错切换迁移案例前戏
docker exec -it redis-node-1 /bin/bash
redis-cli -p 6381
进入6381端口的redis
给k1赋值v1,发现报错:
因为这个数据的槽位超过了6381的所在槽位
我们set k2 v2
就可以:
所以我们要以集群的方式去连接redis:redis-cli -p 6381 -c
c就是cluster集群
这次的数据就可以储存进去了,redirected就说明存到了别的槽位,12706就是槽位
查看集群信息:redis-cli --cluster check 117.21.100.128:6381
6x1.4.2主从容错切换迁移
先停掉一台redisdocker stop redis-node-1
再进入redis2docker exec -it redis-node-2 /bin/bash
redis-cli -p 6382 -c
再输入cluster nodes
查看主从关系
可以看到6381以前和6386配队的
现在6386自己成了主机docker start redis-node-1
再次启动一号机,6381再一次变为6386的master
6X1.4.3 主从扩容
docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis --cluster-enabled yes --appendonly yes --port 6388
创建2个端口分别是87.88的
将6387加入到6381节点中:redis-cli --cluster add-node 117.21.100.128:6387 117.21.100.128:6381
检查一次集群:redis-cli --cluster check 117.21.100.128:6381
表示6387暂时没有槽位
重新分配槽号:redis-cli --cluster reshard 117.21.100.128:6381
输入4096,也就是16384/4
表示四台机器平分
输入我们的6387的ID:
接着输入all,yes
再第二次检测集群:redis-cli --cluster check 117.21.100.128:6381
分配成功
这个6387是从之前三个槽位都分了一点过来
把6388加入6387从属:redis-cli --cluster add-node 117.21.100.128:6388 117.21.100.128:6387 --cluster-slave --cluster-master-id e47664b9814bd0ecf7de8ce648c65fbf44710702
成功加入
4主4从
6X1.4.4 主从缩容
删除一下6388端口机redis-cli --cluster del-node 117.21.100.128:6388 b500976f6a91e61d448f45d8ace8f36d7bf83192
后面一串是check中的节点ID
将6387槽号清空,重新分配给6382:
重新分配槽号redis-cli --cluster reshard 117.21.100.128:6381
先填6382的ID,再填6387的ID,6382接受,6387给槽位
在输入yes
6382接受了槽位
6387的槽位空了
再删除6387的节点redis-cli --cluster del-node 117.21.100.128:6388 e47664b9814bd0ecf7de8ce648c65fbf44710702
7X1 Dockerfile
7X1.1 什么是dockerfile
dockerfile是用来构建docker镜像的文本文件,是由一条条构建镜像所需指令和参数构成的脚本
相当于我们写什么PHP啊,shell脚本这样的
编写三部曲:dockerfile编写脚本>>docker build命令构建镜像>>docker run实现运行容器
dockerfile基础知识:
- 每条保留指令都必须为大写字母且后面要跟至少一个参数
- 指令按照从上往下顺序进行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
7X1.2 Dockerfile保留字节简介
- FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
- MAINTAINER:镜像维护者的姓名和邮箱地址
- RUN:镜像构建时需要运行的命令
有两种格式,shell和exec格式,run在docker build时运行
- EXPOSE:当前容器对外暴露的端口
- WORKDIR:指定在创建容器后,终端默认登入的工作目录,落脚点
- USER:镜像以什么用户去执行,如root
- ENV:设置环境变量
- VOLUME:容器卷
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
- CMD:指定容器启动后要干的事情
dockerfile可以有多个CMD指令,但是只有最后一个会生效,CMD会被docker run后的参数替代
- ENTRYPOINT:
7X1.3 Dockerfile-centos案例
docker pull centos
先pull个centos下来
首先下载下来的centos系统是无法运行vim,ifconfig,java-version指令的
需求:具备vim,ifconfig,jdk8
准备一个jdk8的包,然后在目录下新建dockerfile文件vim Dockerfile
1 | FROM centos:7 |
在当前目录docker build -t centosjava8:1.5 .
成功安装执行dockerfile
之后docker images后可以看到搭建的镜像:
再接着run一个实例容器检查一下指令是否安装:
docker run -it –name=centos-1 centosjava8:1.5 /bin/bash
全部安装完毕
虚悬镜像:
容器构建或者删除时候,出现了错误,就会出现虚悬镜像:
两个都是none,虚悬镜像应该删除
查找虚悬镜像:docker image ls -f dangling=true
docker image prune
或者docker rmi -f id
也可以删除
8X1 Docker network
8X1.1 network常用指令
首先输入在我们启动docker后运行指令ifconfig
后回出现个docker0的虚拟网桥:
docker就是通过这个虚拟网桥来和宿主机交流docker network ls
:查看docker网络模式docker network create 网络名字
:创建一个网络docker network inspect 网络名字
:查看网络配置
8X1.2 docker-network能干嘛
容器间的互联和通信以及端口映射
容器IP变动时可以通过服务名直接网络通信
8X1.3 网络类型
8X1.4 docker底层ip和容器映射变动
这说明这个ip是会变动的
About this Post
This post is written by Boogipop, licensed under CC BY-NC 4.0.