Docker学习总结
Docker简介
Docker 使用客户端-服务器 (C/S) 架构模式,Docker的守护进程运行在主机上。通过Socket从客户端访问
Docker为什么比虚拟机快
- Docker比虚拟机的抽象层更少
- Docker共享操作系统内核,每个VM都包含一整套操作系统
新建一个容器时,Docker不需要像虚拟机一样重新加载一个操作系统内核,避免了引导操作
Docker镜像运行流程
Docker安装Nginx
-
执行
docker search nginx
查询是否有nginx镜像,推荐去 dockerhub上搜索
-
找到nginx后执行
docker pull nginx
拉取nginx镜像
- 默认拉取最新版的
- 需要其他版本的镜像,请去dockerhub搜索
-
执行
docker images
查看是否拉取下来 -
执行
docker run -d --name nginx -p 80:80 nginx
运行nginx。运行命令解析
-d 后台模式运行
–name nginx 启动容器名为nginx
-p 8089:80 将容器的80端口映射到主机的8089端口上
nginx 要启动的镜像名
-
启动完成后,执行
docker ps
查看容器 -
执行
curl localhost:80
,可以进行本机自测
Docker安装Tomcat
-
执行
docker run -it --rm tomcat:9.0
–rm 表示用完就删除镜像
-
tomcat启动完,在外部网络访问时会报404错误
错误原因
- 这是因为docker这里的tomcat不是完整版的,该镜像是最小版的镜像,会将tomcat中不必要的东西全部删除,
- 容器中的webapps文件夹是空的。
解决方法
-
将主机的tomcat的webapps文件下的所有文件拷贝到容器中
-
进入容器的tomcat文件夹下,在文件夹下会看到一个叫webapps.dist的文件夹
方法一:将webapps.dist改名,改成webapps
方法二:将webapps.dist文件夹下的内容全部拷贝到webapps文件夹下
Docker安装Elasticsearch+Kibana
es需要暴露许多端口
es耗内存严重
es的数据一般需要放置到安全目录。挂载
-
执行
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.8.0
问题
启动后发现服务器很卡
解决办法
增加内存限制
-
修改配置文件
-
-e 环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.8.0
再次执行
docker stats
查看内存情况
-
-
运行
curl localhost:9200
,显示如下信息表示安装成功
-
执行
docker stats
查看内存
可视化
-
portainer
portainer是Docker的图形化管理功接,提供一个后台面板用来操作。
docker run -d -p 8088:9000 \ --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
-
外网通过http://ip:8088访问portainer
-
加载完成后,设置账号密码
-
选择本地的,连接,然后看到下图效果
-
Docker镜像
什么是镜像
镜像 轻量级、可执行的独立软件包;用来打包软件运行环境和基于运行环境开发的软件;包含运行某个软件所需的所有内容(代码、库、环境变量和配置文件)
镜像获取
- 远程仓库下载
- 存储设备拷贝
- 自己制作一个镜像DockerFile
commit镜像
将修改过的容器保存。
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
容器数据卷
什么是容器数据卷
数据卷:数据卷就是在宿主中可以在容器之间进行共享和重用的一系列文件和文件夹,通过docker run -v命令可以将数据卷挂载到对应的容器目录空间,进行文件读取,容器卷特性如下
- 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效方便
- 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作
- 对数据卷的更新不会影响镜像,解耦了应用和数据
- 卷会一直存在,直到没有容器使用,可以安全地卸载它
数据卷容器:
1. 提供数据卷供其他容器挂载。
2. 当数据卷容器宕机后,并不会造成数据卷的回收卸载,数据卷会继续挂载在其他容器中。
3. 当全部挂载该数据卷的容器全部宕机后,该数据卷才会卸载
作用:容器的持久化;容器间继承+共享数据
使用数据卷
命令挂载 -V
docker run -it -v 主机目录:镜像目录 容器名 /bin/bash
启动完成后,使用
docker inspect 容器id
查看卷挂载信息
挂载成功后,当在docker容器内的地址文件下创建新的文件时,主机挂载地址会同步创建一个一样的文件。当容器停止后,在主机上修改完文件内容。此时我们再次重启刚才的容器,会发现容器中绑定的文件也会被同步修改。挂载卷的数据同步是双向的
具名和匿名挂载
匿名挂载
docker run -d -p --name nginx -v /etc/nginx nginx
查看所有volume的信息
docker volume ls
具名挂载
docker run -d -p --name nignx01 -v jm-nginx:/etc/nginx nginx
匿名挂载、具名挂载和指定路径挂载区别
-v 容器内路径 匿名挂载
-v 卷名:容器内路径 具名挂载
-v /主机路径:容器内路径 指定路径挂载
docker run -d -p --name nignx01 -v jm-nginx:/etc/nginx:ro nginx
docker run -d -p --name nignx01 -v jm-nginx:/etc/nginx:rw nginx
加上:
ro
或rw
可以改变读写权限
- ro:read only 只读
- 只能通过主机操作,容器内部无法操作
- re:read write 可读可写
Docker安装MySQL
-
拉取镜像
docker pull mysql:5.7
-
运行容器时将数据挂载,
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=12345678 --name mysql57 mysql:5.7
-e 配置MySQL环境
-
当把容器删除了,挂载到本地的数据不会被删除。
Dockerfile
Dockerfile是用来构建docker镜像的构建文件
通过此脚本可以生成镜像,镜像是一层一层的脚本命令
创建一个dockerfile文件
mkdir 文件名
文件内容: 指令(大写) 参数
FROM centos VOLUME ["volume01","volume02"] CMD echo "-------end-------" CMD /bin/bash
启动自己创建的镜像
这两个挂载是匿名挂载,同样会同步。
构建镜像是没有挂载卷,后面就需要手动通过
-v 卷名:容器内路径
进行挂载
构建步骤:
- 创建编写一个dockerfile文件
- 执行
docker build
命令构建成一个镜像 - 执行
docker run
命令运行镜像 - 执行
docker push
命令发布镜像
dockerfile基础
- 每个保留关键字(指令)都必须是大写的
- 执行顺序从上到下
- 注释用
#
- 每个指令都会创建一个新的镜像层,并提交。
Dockerfile:构建文件,定义了一切的步骤,源代码
DockerImages:通过Dockerfile构建生成的镜像,最终发布和运行的产品
Docker容器:镜像运行起来提供服务器
Dockerfile指令
- FROM 基础镜像,构建开始
- MAINTAINER 镜像是谁写的,姓名+邮箱
- RUN 镜像构建时需要运行的命令
- ADD 添加内容,如tomcat镜像,MySQL镜像…
- WORKDIR 镜像的工作目录
- VOLUME 挂载目录
- EXPOSE 保留端口配置
- CMD 指定容器启动时要运行的命令,只有最后一个会生效,可被替代
- ENTRYPOINT 指定容器启动时要运行的命令,可以追加命令
- ONBUILD 当构建要给被继承Dockerfile时会运行ONBUILD指令。触发指令。
- COPY 类似ADD,将文件拷贝到镜像中
- ENV 构建时设置环境变量
例子:
创建编写dockerfile文件
FROM centos MAINTAINER 作者<邮箱> ENV MYPATH /usr/local WORKDIR $MYPATH RUN yum -y install vim RUM yum -y install net-tools EXPOSE 80 CMD echo $MYPATH CMD echo "----------END-------------" CMD /bin/bash
构建镜像
docker build -f dockerfile文件名 -t 镜像名:[TAG] .
测试运行
查看本地进行的变更历史:docker history 容器id
Dockerfile制作tomcat镜像
- 准备tomcat和jdk的压缩包
官方命名
Dockerfile
,构建时会自动寻找该文件,故不需要用-f
指定文件
创建编写dockerfile文件
FROM centos MAINTAINER 作者<邮箱> COPY readme.txt /usr/local/readme.txt ADD jdk-8u241-linux-x64.tar.gz /usr/local/ ADD apache-tomcat-9.0.36.tar.gz /usr/local/ RUN yum -y install vim ENV MYPATH /usr/local WORK $MYPATH ENV JAVA_HOME /usr/loacl/jdk1.8.0_241 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/loacl/apache-tomcat-9.0.36 ENV CATALINA_BASH /usr/loacl/apache-tomcat-9.0.36 ENV PATH $PATH:\$JAVA_HOME/bin:\$CATALINA_HOME/lib:\$CATALINA_HOME/bin EXPOSE 8080 CMD /usr/loacl/apache-tomcat-9.0.36/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.36/bin/logs/catalina.out
构建镜像
docker build -t diytomcat .
启动镜像
docker run -d -p 8080:8080 --name tomcat01 -v /home/hanson/build/tomcat/test:/usr/local/apache-tomcat-9.0.36/webapps/test -v /home/hanson/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.36/logs diytomcat
- 将镜像发布
发布镜像到DockerHub上
- 注册DockerHub
- 执行
docker login -u 用户名 -p
命令登录DockerHub- 执行
docker push 作者/镜像名:[TAG]
发布镜像发布到阿里云镜像服务上
登录阿里云
找到容器镜像服务
创建命名空间
创建容器镜像仓库
浏览仓库信息
数据卷容器
两个或多个容器之间实现数据共享
docker run -it --name 容器名1 --volumes-from 挂载的父容器名 镜像名:[TAG]
当父容器停掉或删掉,挂载的容器1数据不会被删除
多个MySQL实现数据共享
docker run -d -p 3306:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=12345678 --name mysql01 mysql:5.7
docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=12345678 --name mysql02 --volumes-from mysql01 mysql:5.7
数据卷容器的生命周期一直持续到没有容器使用为止。但持久化到本地的数据是不会删除的。
Docker网络
docker是如何处理网络访问?
运行一个容器
docker run -d -P --name tomcat01 tomcat
查看容器内部网络地址
docker exec -it tomcat01 ip a
Linux可以ping通docker容器内部地址
原理
-
每启动一个docker容器,docker就会给docker容器分配一个IP,只要安装了docker,就会有一个docker0网卡。桥接模式,使用的技术是evth-pair技术
-
每启动一个容器,就多一对网卡
evth-pair就是一对虚拟设备接口,都是成对出现的,一端连着协议,一端彼此相连。运用这个特性充当桥梁,连接各种虚拟设备
容器之间可以相互通信。所有容器不指定网络的情况下,都是docker0路由的,dockers会给每个容器分配一个默认的可用IP。
Docker使用的是Linux的桥接,主机中是一个Docker容器的网桥docker0。容器删除,对应的一对网桥就会删除。
场景:编写了一个微服务,database=url=ip;项目不重启,数据库IP换掉,可以通过容器名访问容器
使用
--link
解决容器间网络连通问题
- 就是一个host映射,不建议使用
自定义网络
查看所有的网络docker network ls
网络模式:
1. bridge:桥接docker(默认)
2. none:不配置网络
3. host:和主机共享网络
4. container:容器网络连通(用的少,局限很大)
直接启动命令 --net bridge,这个就是docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
docker特点:默认,域名不能访问,–link可以打通连接
自定义网络:
docker network creat --driver bridge --subnet 192.168.0.0/16 --getway 192.168.0.1 mynet
- –driver bridge 桥接
- –subnet 192.168.0.0/16 子网地址
- –getway 192.168.0.1 网关
不适用--link
也可以ping容器名,推荐使用自定义网络
不通的集群使用不同的网络,保证集群是安全和健康的。
网络连通
使用docker network connect 网络名 容器名
连通之后就是将tomcat01 放到mynet网络下(一个容器两个IP)
Redis集群部署
创建网卡
docker network create redis --subnet 172.31.0.0/16
通过脚本创建六个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-enbaled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.31.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes EOF done
启动服务
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.31.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.31.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \ -v /mydata/redis/node-3/data:/data \ -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.31.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \ -v /mydata/redis/node-4/data:/data \ -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.31.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \ -v /mydata/redis/node-5/data:/data \ -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.31.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \ -v /mydata/redis/node-6/data:/data \ -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.31.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
进入redis容器
docker exec -it redis-1 /bin/sh
创建集群
redis-cli --cluster create 172.31.0.11:6379 172.31.0.12:6379 172.31.0.13:6379 172.31.0.14:6379 172.31.0.15:6379 172.31.0.16:6379 --cluster-replicas 1
Springboot微服务打包Docker镜像
- 构建spring boot项目
- 打包应用
- 编写Dockerfile
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar"]
- 构建镜像
docker build -t 镜像名 .
- 发布运行