深入浅出Docker
Docker概述
基于GO语言开发 Docker的思想来自于集装箱。Docker通过隔离机制,额可以将服务器利用到极致。 隔离:Docker核心思想,打包装箱,每个箱子都是相互隔离的。
Docker的历史
'dotcloud' --> 做一些pass云计算服务,LXC有关的容器技术,将自己的容器化技术命名 --> Docker. Docker十分的轻巧。在容器技术出现之前,一直都是虚拟机技术. 虚拟机:在window中安装一个Vmware,通过这个软件我们可以虚拟出来一台或多台电脑。笨重。 虚拟机也属于虚拟化技术,Docker容器技术亦然。 vm linux centos原生镜像 隔离 需要多个虚拟机 G为单位 docker 隔离 镜像(最核心的环境4m + jdk + mysql)十分小巧,运行镜像即可。 M为单位 秒级启动
到现在,所有的开发人员都必须会使用docker.
聊聊Docker
docker能干啥??
之前的虚拟机技术
虚拟机技术缺点:
资源占用十分多
冗余步骤多
启动很慢
容器化技术
容器化技术不是模拟一个完整的操作系统
比较Docker和虚拟机技术的不同:
传统虚拟机,虚拟出一条硬件,运行一个完成的操作系统,然后在这个系统上安装和运行软件
容器内应用直接运行在宿主机上,容器内是没有自己的内核的,也没有虚拟我们的硬件,所以轻便
每个容器间互相隔离,每个容器内都有属于自己的文件系统,互不影响
DevOps(开发 运维)
应用更快速的的交付和部署 传统:阅读帮助文档,开发程序 Docker:打包镜像发布测试,一键运行 更便捷的升级和扩缩容 更简单的系统运维 开发测试环境高度一致 更高效的计算机资源利用 Docker是内核级别的虚拟化,可以在一个物理机上运行更多的容器示例,榨干服务器
Docker的安装
docker的基本组成
Docker为什么比VM更快?
1、Docker有着比虚拟机更少的抽象层
2、docker利用宿主机的内核,vm 需要Guest OS
[图片上传失败...(image-746d47-1600430461687)]
docker常用命令
帮助命令
docker verison
docker info #显示docker的系统信息,包括镜像和容器的数量
镜像命令
docker images #查看所有主机上的镜像
可选项
-a, --all #列出所有镜像
-q, --quiet #只显示镜像的id
docker search [image]
可选项
-f, --filter=STARS=5000
docker pull [镜像名:tag]#下载 分层下载,image的核心,联合文件系统
docker rmi -f [id]
docker rmi -f [id id id id]
docker rmi -f $(docker images -aq) #删除全部的容器
容器命令
说明:有了镜像方能创建容器
docker pull ubuntu
docker run [args] image
--name="name"
-d #后台方式运行
-it #使用交互方式
-p #指定容器的端口
-p 主机端口:容器端口
-p 容器端口
-P #随意指定端口
docker ps #列出所有运行的容器
docker ps -a #列出曾经运行的容器+历史的
-n=? #显示最近运行的容器
exit #直接停止并推出
ctrl +P +Q #容器不停止并退出
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
常用其他命令
docker run -d [image] #后台运行时,需要前台进程,没有前台服务会自动停止
docker logs #查看日志
编写一个shell脚本
docker run -d ubuntu:latest /bin/sh -c "while true;do echo summer;sleep 1;done"
docker logs -tf --tail 10 id
查看容器中进程的信息
docker top id
docker inspect id #查看容器的信息
进入当前正在运行的容器
docker exec -it id /bin/bash #进入容器后开启一个新的终端
docker attach id #进入正在执行的命令行,不会启动新的进程
从容器内拷贝到主机上
docker cp id:容器内路径 目标路径
拷贝是一个手动过程,后期会通过 -v 卷实现自动同步
基础命令小结
[图片上传失败...(image-a0f697-1600430461687)]
Docker安装nginx
#搜索nginx
docker search nginx
下载
docker pull nginx
运行并测试
docker run -d --name nginx01 -p:3344:80 nginx
curl localhost:3344
docker exec -it nginx01 /bin/bash
端口暴露
[图片上传失败...(image-169bff-1600430461687)]
Docker安装tomcat
# 官方使用 一般用来测试 用完就删除
docker run -it --rm tomcat:9.0
我们之前的启动都是后台,停止之后还是可以查到的
docker run -d -p 3355:8080 --name tomcat01 tomcat
测试访问没有问题 但是页面为404 这是因为阉割版的tomcat
linux命令少了 缺少webapp的内容
解决方法 将webapps.dist cpoy
cp -r /webapps.dist/* /webapps
访问成功
如何在容器外部修改,避免每次进入容器
部署es + kibana
# es 暴露的端口很多 十分的耗内存
下载并启动
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
查看CPU状态
docker stats
修改配置文件 增加内存限制
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPT="-Xms64m -Xmx512m" Selasticsearch:7.6.2
Docker网络原理
[图片上传失败...(image-21f2ab-1600430461687)]
可视化
portainer
Rancher(CI/CD)
什么是portainer?
docker图形化界面管理工具,提供一个后台面板供我们操作
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
Docker镜像讲解
所有应用,直接打包docker镜像,就可以直接跑起来
Docker镜像加载原理
UnionFS(联合文件系统)
UnionFS(联合文件系统):一种分层/轻量级并且高性能的文件系统,它支持对文件系统的修改来作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS文件系统是Docker镜像的基础。镜像可以通过分层来继承,基于基础镜像,可以制作各种具体的应用镜像。
下载时出现的层级关系就是如此.
特性:一次同时加载多个文件系统,但是从外面只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要引导加载kernal,Linux刚启动时会加载bootfs文件系统,在docker镜像的最底层时bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核,当boot加载完成之后整个内核就在内存之中,此时内存的使用权已有bootfs转交给内核,此时系统也会卸载bootfs
rootfs,在bootfs之上,包含的就是典型的Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件.rootfs就是各种不同的操作系统发行版,比如ubuntu,CentOS等等
[图片上传失败...(image-206d26-1600430461686)]
对于精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了.由此可见对于不同的linux发行版,bootfs基本一致,rootfs会有差别,因此不同的发行版本可以公用bootfs
虚拟机是分钟级 容器时秒级
分层理解
已经下载的就不用下了
docker image inspect redis:latest #查看RootFS
commit镜像
docker commit image
docker commit -m="message" -a="summer" id [image:tag]
容器数据卷
什么是容器数据卷
容器之间需要有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载!
方式一:使用命令挂载
docker run -it -v 主机目录:容器目录
docker inspect #查看容器配置信息
实战MySQL
数据持久化问题
docker pull mysql
运行时做数据挂载
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123123 --name mysql01 mysql
[图片上传失败...(image-fa4c3d-1600430461686)]
具名和匿名挂载
# 匿名挂载
-v 容器内路径名
docker run -d -P --name nginx01 -v /etc/nginx nginx
查看所有卷的情况
docker volume ls
具名挂载就是指定挂载目录的地址
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
设置容器权限
docker run -d -P --name nginx02 -v summer-nginx:/etc/nginx:ro nginx #内容只能通过宿主机来操作 容器是无法操作的
docker run -d -P --name nginx02 -v summer-nginx:/etc/nginx:ro nginx
初识DockerFile
Dockerfile就是用来构建docker镜像的构建文件
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层
# create a dockerfile
FROM ubuntu
VOLUME ["volume01","volume02"]
CMD echo "---end---"
CMD /bin/bash
docker build -f ./dockerfile -t summer/ubuntu:1.0 .
数据卷容器
两个mysql同步数据 --volumes-from
[图片上传失败...(image-f1b4ec-1600430461686)]
docker run -it --name docker03 --volumes-from docker01 image:tag
删除docker01后,docker03依旧能够访问挂载文 件
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
Dockerfile
编写一个dockerfile文件
docker build 构建成为一个镜像
docker run 运行镜像
docker push发布镜像(DockerHub,阿里云镜像仓库)
DockerFile指令
[图片上传失败...(image-81718c-1600430461686)]
实战测试
创建一个centos 视频示例
FROM centos
MAINTAINER [email protected]
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
爷的示例 Ubuntu中安装vim和inetutils-ping
FROM ubuntu
MAINTAINER [email protected]
ENV MYPATH /usr/local #pwd展示的目录,工作目录
RUN apt-get update #先更新源
RUN apt-get -y install vim
RUN apt-get -y install inetutils-ping
EXPOSE 8028
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
依旧有debconf:delaying package configuration,since apt-utils is not installed
docker history id #查看安装的工作历史
CMD 和 ENTRYPOINT的区别 (追加命令测试)
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
测试cmd
FROM ubuntu
CMD ["ls","-a"]
# 想追加一个 'l' 构成 ls -al 此时需要使用ENTRYPOINT
docker run id ls -al
Tomcat镜像文件
准备镜像文件tomcat的压缩包,jdk压缩包
编写dockerfile文件
FROM ubuntu
MAINTAINER [email protected]
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u212-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-7.0.105.tar.gz /usr/local/
RUN apt-get update
RUN apt-get -y install vim
ENV MYPATH /usr/local/
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_212
ENV CLASSPATH JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-7.0.105
ENV CATALINA_BASH /usr/local/apache-tomcat-7.0.105
ENV PATH JAVA_HOME/bin:CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-7.0.105/bin/startup.sh && tail -F /usr/local/apache-tomcat-7.0.105/logs/catalina.out #此处有问题 导致无法启动tomcat
CMD echo "----end----"
(base) summer@summer-ubuntu:/home/docker-test-volumeMYPATH
---> Running in 25a3b17f9cd8
Removing intermediate container 25a3b17f9cd8
---> 1ae1442a37f0
Step 10/17 : ENV JAVA_HOME /usr/local/jdk1.8.0_212
---> Running in fa66f8f1ac7c
Removing intermediate container fa66f8f1ac7c
---> a0ef0558e23f
Step 11/17 : ENV CLASSPATH JAVA_HOME/lib/tools.jar
---> Running in 6e1d969e6c70
Removing intermediate container 6e1d969e6c70
---> efbeb08d1c25
Step 12/17 : ENV CATALINA_HOME /usr/local/apache-tomcat-7.0.105
---> Running in 402474d2c486
Removing intermediate container 402474d2c486
---> 5ac873f2766a
Step 13/17 : ENV CATALINA_BASH /usr/local/apache-tomcat-7.0.105
---> Running in f61cd128c180
Removing intermediate container f61cd128c180
---> 14d213898d39
Step 14/17 : ENV PATH JAVA_HOME/bin:CATALINA_HOME/bin
---> Running in 12da6c314b92
Removing intermediate container 12da6c314b92
---> 6dd48e24f077
Step 15/17 : EXPOSE 8080
---> Running in 629beda656c7
Removing intermediate container 629beda656c7
---> 4893cb8ce3e6
Step 16/17 : CMD /usr/local/apache-tomcat-7.0.105/startup.sh && tail -F /usr/local/apache-tomcat-7.0.105/bin/logs/catalina.out
---> Running in 33822deeddf8
Removing intermediate container 33822deeddf8
---> 5a66e5f51ea2
Step 17/17 : CMD echo "----end----"
---> Running in aacb08595dd0
Removing intermediate container aacb08595dd0
---> 6ea98729bf64
Successfully built 6ea98729bf64
Successfully tagged summercat:1.0
# 创建容器并挂载
docker run -it --name summercat:1.0 -p 9090:8080 -v /home/summer/build/tomcat/test:/usr/local/apache-tomcat-7.0.105/webapps/test -v /home/summer/build/tomcat/logs:/usr/local/apache-tomcat-7.0.105/logs summercat:1.0 /bin/bash
发布项目(由于做了挂载,我们直接在本地编写项目就可以发布)
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
hello summer
Hello docker!
<%
out.println("你的 IP 地址 " + request.getRemoteAddr());
%>
原来这就是发布啊!!
发布自己的镜像dockerhub
https://hub.docker.com/ 账号
登录
提交镜像
docker login -u name
docker push summer/images:1.0
发布自己的镜像到阿里云
登陆阿里云,找到容器服务
创建命名空间
创建容器镜像
看阿里云教程
Docker网络
#启动tomcat
docker run -d -P --name mycat tomcat
查看容器内地址 docker分配了一个eth0@if2
docker exec -it mycat ip addr
#容器外
ping 172.17.0.2 #success
原理
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术!
容器带来的网卡都是一对对出现的,evth-pair就是一对虚拟设备接口,一段连着协议,一段彼此相连,充当一个桥梁,连接各种虚拟网络设备
结论:容器与容器之间是能够ping通的
[图片上传失败...(image-21a7a4-1600430461686)]
结论:docker0是一个公用的路由器
所有容器在不指定网络的情况下,docker0会给他们分配一个默认的可用IP
Docker使用的是linux的桥接,宿主机中是一个Docker容器的网桥docker0
docker中所有的网络接口都是虚拟的,虚拟的转发效率高(内网贼快的好吧)
[图片上传失败...(image-f33e77-1600430461686)]
--link
思考一个场景,编写一个微服务,database url = ip,项目不重启,数据库IP换掉,我们希望可以通过名字来进行访问容器。
docker exec -it mycat02 ping mycat
docker run -it -P --name mycat03 --link mycat02 tomcat bash
但是方向无法ping通
docker network ls
docker network inspect id
(base) summer@summer-ubuntu:~/build/tomcat/logs$ docker network inspect 1a4c1965e38b
[
{
"Name": "bridge",
"Id": "1a4c1965e38bec706e5510466cd7e926f6bac2543f07919f2b6a8a58317621ca",
"Created": "2020-09-08T21:01:49.380468428+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"8d20d8c0d1bc3af2a31ba3e46eba90981815c38755a0f2be5acaee44f4030339": {
"Name": "mycat02",
"EndpointID": "2368a70e8b1148c852f612c71ad25191ef1d2efa5630885324882e90a30b393f",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"b78c76859a085802c80be34b5fde497a2b5cc005ea63ead1b646e21ac9f5a452": {
"Name": "mycat",
"EndpointID": "ff13e65d8197c73f0556db6f91172d51abb278b1276c3509677ad76e91f80e13",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"e119826d2a769803ce6fbea2db2f907e7a44d07e4eed0b3a2c845cf8bd63c074": {
"Name": "mycat03",
"EndpointID": "d3bedf123842c0edb561e28a853f35289c271de6ca8e012cc164058eb49f37b3",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
本质探究: --link使得hosts文件中增加一行配置信息
现在不推荐使用 --link
自定义网络不适用docker0
docker0的问题:不支持容器名连接访问
自定义网络
网络模式:
bridge :桥接docker(默认)
none :不配置网络
host :和宿主机共享网络
container :容器网络联通(用得少,局限大)
测试
# --net bridge 就是docker0,默认,域名不能访问,--link能狗打通链接
docker run -d -P --name tomcat01 --net birdge tomcat
--subnet 192.168.0.0/16 192.168.0.1 192.168.255.255
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 这样就可以ping名字了
docker -d -P --name tomcat-net-01 --net mynet tomcat
docker network inspect mynet
# 新建容器 测试名字访问
自定义的网络不使用--link也能连接成功
网络联通
#一个容器两个地址
docker network connect mynet tomcat01
实战:部署Redis集群
[图片上传失败...(image-d7293d-1600430461686)]
#1. 创建网卡
docker network create redis --subnet 172.38.0.0/16
2. 通过脚本创建六个redis配置
for port in port/conf
touch /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-port 16379
appendonly yes
EOF
done
3. 启动
docker run -p 6371:6379 -p 16371:16379 --name redis-1
-v /mydata/redis/node-1/data:/data
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2
-v /mydata/redis/node-2/data:/data
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
如上整六个
# 别如上了 看下面
for p in p:6379 -p 1637p -v /mydata/redis/node-p/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1$p redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done
启动成功 看下图
#进入容器瞅一瞅 不截图了
docker exec -it redis-1 /bin/sh #没有bash 只能sh
4. 创建集群
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
redis错误定位
这报错看不懂呀 学完redis再来吧
#
redis-cli -s
cluster info
cluster nodes
SpringBoot微服务打包为docker镜像
架构springboot项目
打包应用
编写dockerfile
构建镜像
发布运行
看看就好了
docker基础篇到此为止。那么问题来了,如果有很多镜像,上百个,这该怎么办,且听下回分解。