初识Docker
Docker
Docker安装前置条件
修改配置
vim /etc/selinux/config
重启linux
Docker的基本组成
镜像(image)
docker镜像就好比是一个目标,可以通过这个目标来创建容器服务,通过这个镜像可以创建多个容器。
容器(container)
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建。
仓库(repository)
仓库就是用来存放镜像的地方。仓库分为公有仓库和私有仓库。
底层原理
为什么Docker比Vm快
1、docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在cpu、内存利用率上docker将会在效率上有明显的优势。
2、docker利用的是宿主机的内容,而不需要Guest OS。
因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。从而避免引导、加载操作系统内核等比较费时费资源的过程。
Docker常用命令
帮助命令
docker version #显示docker的版本信息
docker info #显示docker的系统信息,包括镜像和容器的数量
docker --help #帮助命令
镜像命令
docker images #查看所有本地主机上的镜像,可以使用docker image li代替
docker search #搜索镜像
docker pull #下载镜像
docker rmi #删除镜像
容器命令
docker run 镜像id #新建容器并启动
-d #后台进程运行
--name #命名容器名
-p #指定映射端口
-e #修改配置文件或者环境配置
docker ps #列出所有运行的容器
-a, --all #列出当前正在运行的容器 + 带出历史运行过的容器
-n=?, --last int #列出最近创建的?个容器 ?为1则只列出最近创建的一个容器,为2则列出2个
-q, --quiet #只列出容器的编号
docker rm 容器id #删除指定的容器
docker rm -f $(docker ps -aq) #删除所有的容器
docker ps -a -q|xargs docker rm #删除所有的容器
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #强制停止当前容器
exit #容器直接退出
ctrl+P+Q #容器不停止退出
docker logs -t --tail n 容器id #查看n行日志
docker logs -ft 容器id #跟着日志
docker inspect 容器id #查看镜像的元数据(挂载卷等)
docker exec -it 容器id /bin/bash #进入当前容器后开启一个新的终端,可以在里面操作。
docker attach 容器id #进入容器正在执行的终端
docker cp 容器id:容器内路径 主机目的路径 #从容器内拷贝到主机上
docker commit m="描述信息" -a="作者" 容器id 目标镜像名:[版本TAG] #提交容器成为一个新的副本
docker update redis --restart=always #开机自启动redis
容器数据卷
什么是容器数据卷
容器之间可以有一个数据共享的技术,Docker容器中产生的数据,同步到本地,这就是卷技术。目录的挂载,将我们容器内的目录挂载到Linux上面。
使用数据卷
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口
实战:安装MySql
# 获取mysql镜像
docker pull mysql:5.7
# 运行容器,需要做数据挂载,安装启动mysql,需要配置密码!!
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
具名和匿名挂载
匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有的volume(卷)的情况
docker volume ls
DRIVER VOLUME NAME # 容器内的卷名(匿名卷挂载)
local 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
# 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!
具名挂载
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
-P:表示随机映射端口
# 查看所有的volume(卷)的情况
$ docker volume ls
DRIVER VOLUME NAME
local 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
local juming-nginx #多了一个名字
# 通过 -v 卷名:查看容器内路径
# 查看一下这个卷
$ docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-05-23T13:55:34+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", #默认目录
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/自定义的卷名/_data下,如果指定了目录,docker volume ls是查看不到的。
区分三种挂载方式
# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的
Dockerfile
Dockerfile就是用来构建docker镜像的构建文件,通过这个脚本可以生成镜像,镜像是一层层的,脚本是一个个的命令,每个命令都是一层。
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建称为一个镜像
3、docker run 运行镜像
4、docker push发布镜像(DockerHub、阿里云仓库)
# 创建一个dockerfile文件
# 文件中的内容:指令(大写)+参数
vim dockerfile1
FROM centos # 当前这个镜像是以centos为基础的
VOLUME ["vokume01","volume02"] # 挂载卷的卷目录列表(多个目录)
CMD echo "------end------" # 输出以下用于测试
CMD /bin/bash # 默认走bash控制台
# 这里的每个命令,就是镜像的一层
# 构建出这个镜像
docker build -f dockerfile1 -t csp/centos .
-f # 代表file,指dockerfile当文件的地址
-t # 代表target,指目标目录(注意csp镜像名前不能加斜杠'/')
. # 表示生成在当前目录下
多个mysql实现数据共享
$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
$ docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
# 这个时候,可以实现两个容器数据同步!
结论:
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的。
构建过程
1、每个保留关键字都是必须是大写字母
2、顺序执行从上到下
3、每一个指令都会创建提交一个新的镜像层,并提交。
DockerFile的指令
FROM # from:基础镜像,一切从这里开始构建
MAINTAINER # maintainer:镜像是谁写的, 姓名+邮箱
RUN # run:镜像构建的时候需要运行的命令
ADD # add:步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR # workdir:镜像的工作目录
VOLUME # volume:挂载的目录
EXPOSE # expose:保留端口配置
CMD # cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令
COPY # copy:类似ADD,将我们文件拷贝到镜像中
ENV # env:构建的时候设置环境变量!
我们平时拿到一个镜像,可以用“docker history 镜像id”研究一下是什么做的。
实战:Tomcat镜像
1、准备镜像文件
准备tomcat和jdk到当前目录,编写好README
2、编写dockerfile
$ vim dockerfile
FROM centos # 基础镜像centos
MAINTAINER CSP<XXX@qq.com> # 作者
COPY README /usr/local/README # 复制README文件
ADD jdk-8u231-linux-x64.tar.gz /usr/local/ # 添加jdk,ADD 命令会自动解压
ADD apache-tomcat-9.0.35.tar.gz /usr/local/ # 添加tomcat,ADD 命令会自动解压
RUN yum -y install vim # 安装 vim 命令
ENV MYPATH /usr/local # 环境变量设置 工作目录
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_231 # 环境变量: JAVA_HOME环境变量
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.35 # 环境变量: tomcat环境变量
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.35
# 设置环境变量 分隔符是:
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080 # 设置暴露的端口
CMD /usr/local/apache-tomcat-9.0.35/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.35/logs/catalina.out # 设置默认命令
3、构建镜像
# 因为dockerfile命名使用默认命名 因此不用使用-f 指定文件
$ docker build -t mytomcat:0.1 .
4、run镜像
# -d:后台运行 -p:暴露端口 --name:别名 -v:绑定路径
$ docker run -d -p 8080:8080 --name tomcat01
-v /home/build/tomcat/test:/usr/local/apache-tomcat-9.0.35/webapps/test
-v /home/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.35/logs mytomcat:0.1
5、访问测试
$ docker exec -it 自定义容器的id /bin/bash
$ cul localhost:8080
6、发布项目
Docker网络
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个docker0桥接模式,使用的技术是veth-pair技术。
veth-pair相关知识:https://www.cnblogs.com/bakari/p/10613710.html
网络模型
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip。
Docker使用的是Linux的桥接,宿主机是一个Docker容器的网桥docker0。
Docker中所有网络接口都是虚拟的,虚拟的转发效率高(内网传递文件)。只要容器删除,对应的网桥一对就没了。
自定义网络
docker network
connect -- Connect a container to a network
create -- Creates a new network with a name specified by the
disconnect -- Disconnects a container from a network
inspect -- Displays detailed information on a network
ls -- Lists all the networks created by the user
prune -- Remove all unused networks
rm -- Deletes one or more networks
查看所有的docker网络
docker network ls
网络模式
1、bridge:桥接docker(默认,自己创建也是用bridge模式)
2、none:不配置网络,一般不用
3、host:和所有主机共享网络
4、container:容器网络连通(用的少,局限很大)
# 我们直接启动的命令 --net bridge,而这个就是我们得docker0
# bridge就是docker0
$ docker run -d -P --name tomcat01 tomcat
等价于 => docker run -d -P --name tomcat01 --net bridge tomcat
# docker0,特点:默认,域名不能访问。 --link可以打通连接,但是很麻烦!
# 我们可以自定义一个网络
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 启动两个tomcat,再次查看网络情况
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
# 查看网络情况
docker network inspect mynet
在自定义的网络下,服务可以互相ping通,不用使用-link。
假设要跨网络操作别人,需要使用docker network connect连通。
实战:部署Redis集群
# 创建网卡
docker network create redis --subnet 172.38.0.0/16
# 通过脚本创建6个redis配置
for port in $(seq 1 6);
do
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >> /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 通过脚本运行6个redis
for port in $(seq 1 6);
docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker exec -it redis-1 /bin/bash
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
限制docker容器与宿主机以外的机器互通
1、创建一个新链接BEFORE_DOCKER
iptables -N BEFORE_DOCKER
2、配置BEFORE_DOCKER只能连接宿主机172.20.0.1
iptables -I BEFORE_DOCKER -j DROP
iptables -I BEFORE_DOCKER -i ens160 -s 172.20.0.1 -j ACCEPT
3、创建一个c断为172.20.0.0/24的docker网络docker1
docker network create --subnet=172.20.0.0/24 --opt "com.docker.network.bridge.name"="docker1" docker1
4、将docker网络docker1的外发规则绑定到BEFORE_DOCKER
iptables -I FORWARD -o docker1 -j BEFORE_DOCKER
保存镜像
docker save -o django_uwsgi-v3.img django_uwsgi:v3
加载镜像
docker load --input django_uwsgi-v3.img