Docker
Docker官网:http://www.docker.com
Docker中文网站:https://www.docker-cn.com
Docker Hub官网:https://hub.docker.com (仓库)
1-4节为Docker入门阶段,基本使用和命令
5-8节为Docker精髓【暂时学到这,等下个月在学】
9-12节为进阶
1、Docker概述
Docker为什么出现
开发与运维环境的配置,各种版本问题。换服务器需要重写配置。还会出现莫名的各种问题。
docker理念为Docker镜像的设计,使得Docker得以打破过去「程序即应用」的观念。通过Docker镜像 ( images ) 将应用程序所需要的系统环境,由下而上打包,达到应用程序跨平台间的无缝接轨运作。
docker是代码+环境的集装箱。
docker的历史
dotCloud,后生存困难,决定开源,
开源后引来越来越多的人支持。
在容器技术之前,虚拟机已经很火。虚拟机技术的代表,是VMWare和OpenStack
虚拟机属于虚拟化技术。而Docker这样的容器技术,也是虚拟化技术,属于轻量级的虚拟化。
docker理念
Docker是基于Go语言实现的云开源项目
Docker的主要目标是“Build,Ship and Run Any App , Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。将应用运行在Docker 容器上面,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
之前的虚拟机技术
虚拟机(virtual machine)就是带环境安装的一种解决方案。
虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。
虚拟机的缺点:资源占用多,冗余步骤多,启动慢
容器虚拟化技术
由于前面虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。
比较了 Docker 和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件,运行一个完整操作系统,再运行所需应用进程;
- 而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区计算资源。
开发/运维(DevOps)
-
快捷交付和部署
-
传统:一堆帮助文档,安装程序
-
Docker:打包镜像发布测试,一键运行
-
-
更便捷的升级和扩缩容
-
软件的版本,环境版本的升级
-
拓展服务器
-
-
更简单的系统运维
- 开发与测试环境高度一致
-
更高效的计算资源利用
- Docker是内核级别的虚拟化,占用资源极小
2、Docker安装
2.1、Docker的基本组成
Docker架构图
镜像(image):
Docker镜像相当于一个模板,可以通过这个模板来创建容器服务,比如tomcat镜像==>run==>tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)
容器(container):
Docker利用容器技术,独立运行一个或者一个组应用,通过镜像俩创建的。
启动,停止,删除,基本命令。(可以暂时理解为一个简易的linux的系统)
仓库(repository):
仓库就是存放镜像的地方,
仓库分为公有仓库和私有仓库
Docker Hub(默认是国外的)
我们需要配置阿里云等(容器服务器,配置镜像加速)
2.2、安装Docker
Linux的环境检测(确保centos7以上版本):
查看自己的内核:
uname -r
命令用于打印当前系统相关信息(内核版本、硬件架构、主机名称和操作系统类型等)。
[root@lxw ~]# uname -r
4.18.0-193.28.1.el8_2.x86_64
查看版本信息:
[root@lxw ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"
正式安装:
1、官网安装参考手册:https://docs.docker.com/engine/install/centos/
2、确定你是CentOS7及以上版本,我们已经做过了
3、yum安装gcc相关环境(需要确保 虚拟机可以上外网 )
yum -y install gcc
yum -y install gcc-c++
4、卸载旧版本(未安装过忽略)
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
5、需要的安装包
yum install -y yum-utils
6、设置镜像仓库
官方(如果很慢就去找国内源)
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
7、更新yum软件包索引
yum makecache
8、安装docker ce (ce社区版,ee企业版)
yum install docker-ce docker-ce-cli containerd.io
9、启动docker
systemctl start docker
10、测试命令
docker version
docker run hello-world
docker images
11、卸载docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
2.3、阿里云镜像加速
1、找到容器镜像服务->镜像加速器
2、配置使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://40l6kzfq.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
2.4、底层原理
docker的运行流程
底层原理
Docker是怎么工作的
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问。
Docker-Server接收到Docker-Client的指令,就会执行这个命令。
为什么Docker比较 VM 快
1.docker有着比虚拟机更少的抽象层,docker不需要Hypervisor实现硬件资源虚拟化,运行在
docker容器上的程序直接使用的都是实际物理机的硬件资源。
2.docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。仍而避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。
3、Docker常用命令
帮助文档:https://docs.docker.com/engine/reference/run/
3.1、帮助命令
docker version # 显示 Docker 版本信息。
docker info # 显示 Docker 系统信息,包括镜像和容器数。。
docker --help # 帮助
3.2、镜像命令
docker images
[root@lxw /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 5 weeks ago 13.3kB
[root@lxw /]# docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet Only show image IDs
解释:
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像创建时间
SIZE 镜像大小
-a 列出所有本地镜像
-q只显示镜像id
docker search
images网页搜索:https://hub.docker.com/
命令:
docker search mysql
docker search --help
docker search mysql --filter=STARS=3000
此时只显示3000以上的
docker pull
docker pull mysql
[root@lxw /]# docker pull mysql
Using default tag: latest # 默认是lastest
latest: Pulling from library/mysql
b380bbd43752: Pull complete # 分层下载,docker image 的核心 联合文件系统
f23cbf2ecc5d: Pull complete
30cfc6c29c0a: Pull complete
b38609286cbe: Pull complete
8211d9e66cd6: Pull complete
2313f9eeca4a: Pull complete
7eb487d00da0: Pull complete
4d7421c8152e: Pull complete
77f3d8811a28: Pull complete
cce755338cba: Pull complete
69b753046b9f: Pull complete
b2e64b0ab53c: Pull complete
Digest: sha256:6d7d4524463fe6e2b893ffc2b89543c81dec7ef82fb2020a1b27606666464d87
Status: Downloaded newer image for mysql:latest # 真实地址
docker.io/library/mysql:latest
docker pull mysql
等价于docker pull docker.io/library/mysql:latest
指定版本下载
docker pull mysql:5.7
[root@lxw /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
b380bbd43752: Already exists
f23cbf2ecc5d: Already exists
30cfc6c29c0a: Already exists
b38609286cbe: Already exists
8211d9e66cd6: Already exists
2313f9eeca4a: Already exists
7eb487d00da0: Already exists
a71aacf913e7: Pull complete
393153c555df: Pull complete
06628e2290d7: Pull complete
ff2ab8dac9ac: Pull complete
Digest: sha256:2db8bfd2656b51ded5d938abcded8d32ec6181a9eae8dfc7ddf87a656ef97e97
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
[root@lxw /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 938b57d64674 2 weeks ago 448MB
mysql latest ecac195d15af 2 weeks ago 516MB
hello-world latest feb5d9fea6a5 5 weeks ago 13.3kB
docker rmi
# 删除镜像
docker rmi -f 镜像id # 删除单个
docker rmi -f 镜像名:tag 镜像名:tag # 删除多个
docker rmi -f $(docker images -qa) # 删除全部
测试:
3.3、容器命令
说明:有镜像才能创建容器,我们这里使用 centos 的镜像来测试,就是虚拟一个 centos !
docker pull centos
新建容器并启动
docker run [可选参数] image
# 参数说明
--name="Name" 容器名字
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-P 大写的P,随机指定端口
-p 指定容器端口 -p 8080:8080
-p 主机端口:容器端口(常用)
-p 容器端口
-p ip:主机端口:容器端口
测试:
docker run -it centos /bin/bash # 进入contos容器
exit # 退出
列出所有运行中的容器
docker ps # 正在运行
docker ps -a # 列出当前所有正在运行的容器 + 历史运行过的容器
docker ps -l # 显示最近创建的容器
docker ps -n=? # 显示最近n个创建的容器
docker ps -q # 静默模式,只显示容器编号。
退出容器
exit # 直接停止容器并退出
ctrl+P+Q # 容器不停止退出
启动停止容器
docker start (容器id or 容器名) # 启动容器
docker restart (容器id or 容器名) # 重启容器
docker stop (容器id or 容器名) # 停止容器
docker kill (容器id or 容器名) # 强制停止容器
删除容器
docker rm 容器id # 删除指定容器
docker rm -f $(docker ps -a -q) # 删除所有容器
docker ps -a -q|xargs docker rm # 删除所有容器
3.4、其他常用命令
后台启动容器
# 命令
docker run -d 容器名
# 例子
docker run -d centos # 启动centos,使用后台方式启动
# 问题: 使用docker ps 查看,发现容器已经退出了!
# 解释:Docker容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命令,就会自动退出。
# 比如,你运行了nginx服务,但是docker前台没有运行应用,这种情况下,容器启动后,会立即自杀,因为他觉得没有程序了,所以最好的情况是,将你的应用使用前台进程的方式运行启动。
查看日志
docker logs -f -t --tail 容器id
# 例子:我们启动 centos,并编写一段脚本来测试玩玩!最后查看日志
docker run -d centos /bin/sh -c "while true;do echo badwei;sleep 1;done"
docker ps
docker logs -tf --tail 10 3aac18ce2646
查看容器中运行的进程信息,支持 ps 命令参数。
docker top 容器id
docker top 213fdd66bf5a
查看容器/镜像的元数据
docker inspect 容器id
docker inspect 213fdd66bf5a
进入正在运行的容器
方式一docker exec -it 容器id bashShell
docker exec -it 213fdd66bf5a /bin/bash
方式二docker attach 容器id
docker attach 213fdd66bf5a
区别
exec 是在容器中打开新的终端,并且可以启动新的进程
attach 直接进入容器启动命令的终端,不会启动新的进程
从容器内拷贝文件到主机上
docker cp 容器id:容器内路径 目的主机路径
docker ps
docker images
docker run -it centos /bin/bash
mkdir lxw
cd lxw
touch lxw1.java
exit # 退出停止不影响文件复制,只要容器存在就可以复制
docker ps
docker cp 4b4cd2752d39:/lxw/lxw1.java /lxw
3.5、小结
常用命令
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 # 截取容器停止时的退出状态值
3.6、练习1:安装 Nginx
1.搜索nginx镜像(推荐去网站搜索)
docker search nginx
2.拉取nginx镜像
docker pull nginx
3.启动nginx镜像(3500:80将本机3500端口映射到nginx容器80端口)
docker images
docker run -d --name mynginx -p 3500:80 nginx
4.测试访问
curl localhost:3500
5.进入nginx容器:
[root@lxw lxw]# docker exec -it mynginx /bin/bash
root@bc7c8e95e1f7:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@bc7c8e95e1f7:/# cd /etc/nginx
root@bc7c8e95e1f7:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
root@bc7c8e95e1f7:/etc/nginx#
注意:端口暴露的概念
把阿里云的3500端口开放
思考:我们每次改动nginx配置文件,都需要进入容器内部,我们要是可以在容器外部提供一个映射路径就very nice 了
3.7、练习2:安装 tomcat
官方文档的坑:(也不算坑,是一个知识点)
# 官方文档解释
# -it :交互模式
# --rm:容器启动成功并退出以后容器就自动移除,一般在测试情况下使用!
docker run -it --rm tomcat:9.0
1、下载tomcat镜像
docker pull tomcat
2、启动
docker run -d -p 3500:8080 --name tomcat01 tomcat
3、进入tomcat
docker exec -it tomcat01 /bin/bash
cp -r webapps.dist/* webapps
3.8、练习3:部署 es + kibana
es的问题:
端口暴露9200 9300
占用内存大 - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
目录安全问题(数据卷的挂载问题 data、plugins、conf)
启动es测试(不要启动,不要启动,不要启动)
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
启动了之后,完了,卡死了。。。。。
重启服务器。。。
重启服务器之后,docker命令失效,但docker version
正常,报错:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
百度后得到答案:因为没有设置docker开机自启,所以需要启动docker解决
systemctl start docker
1、增加上内存限制启动
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
2、测试访问:
curl localhost:9200
思考es和kibana的连接方式?
3.9、可视化
Portainer(先用这个)(一般不会用,玩玩)
Portainer是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。
安装
docker run -d -p 3500:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
会进入登录界面,设置密码后登录
然后选择local连接
里面会可视化的展示一些信息
Rancher(CI/CD再用这个)
#安装rancher-server
docker run --name rancher-server -p 8000:8080 -v /etc/localtime:/etc/localtime:ro -d rancher/server
#安装agent
docker run --rm --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v1.2.11
http://39.101.191.131:8000/v1/scripts/D3DBD43F263109BB881F:1577750400000:7M0yBzCw4XSxJklD7TpysYIpI
4、Docker镜像讲解
4.1、镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包docker镜像,就可以直接运行。
如何得到镜像:
- 从远程仓库下载
- 拷贝其他人的
- 自己制作DockerFile
4.2、Docker镜像加载原理
UnionFS (联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里的centos才200M?
对于一个精简的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
4.3、分层的理解
分层的镜像
下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
docker pull redis
docker image inspect redis:latest
分层:
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
理解:
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件7 是文件 5 的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4.4、镜像Commit
docker commit 提交容器副本使之成为一个新的镜像!
# 语法
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
1、docker启动tomcat(对tomcat进行修改)
docker run -it -p 3500:8080 tomcat
# 因为webapps中为空,所以复制webapps.dist过去
cp -r webapps.dist/* webapps
访问3500端口,正常显示tomcat主页面(修改成功)
2、将修改后的tomcat容器commit为一个新的镜像,我们以后就可以直接使用我们修改过的镜像
docker commit -a="lxw" -m="add webapps app" a379ed757d16 tomcat02:1.0
3、这个时候,我们自己修改的tomcat就可以直接启动运行了
docker run -it -p 8080:8080 tomcat02:1.0
理解:
如果你想保存当前容器,类似于虚拟机VM快照,就可以通过commit提交一个新的镜像版本。下次可以直接运行。
5、容器数据卷
5.1、什么是容器数据卷
docker的理念回顾:
将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够持久化的!
就好比,你安装一个MySQL,如果没有commit存为新镜像,就把mysql容器删了,就相当于删库跑路了,这显然不行!
为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除而丢失了!
作用:
卷就是目录或者文件,存在一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
特点:
1、数据卷可在容器之间共享或重用数据
2、卷中的更改可以直接生效
3、数据卷中的更改不会包含在镜像的更新中
4、数据卷的生命周期一直持续到没有容器使用它为止
所以:总结一句话: 就是容器的持久化,以及容器间的继承和数据共享!
5.2、使用数据卷(mysql)
挂载数据卷的方式一:容器中直接使用命令来添加
挂载
# 命令
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
# 测试
docker run -it -v /home/ceshi:/home centos /bin/bash
查看数据卷是否挂载成功
docker inspect d5698b357dd6
docker容器的/home
与主机的/home/ceshi
双向绑定,所以无论在哪边操作,另一边都会同步。
然后我们关掉docker容器后,只要容器存在,数据依旧同步。比如我们在主机新建test3.java,然后重新启动docker容器,发现test3.java存在于docker容器的/home
下
touch test3.java
docker start d5698b357dd6
docker attach d5698b357dd6
使用 docker 安装 mysql
思考:mysql 数据持久化的问题!
1、拉取镜像
docker pull mysql:5.7
2、启动容器
# -d 后台运行
# -p 端口映射
# -v 卷挂载
# -e 环境配置
# --name 容器名字
docker run -d -p 3500: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
3、本地navicat连接mysql,进行操作,观察
navicat新建数据库,发现与docker容易绑定的本地/home/mysql/data
目录下新增了数据库badwei
4、删除mysql容器
docker rm -f mysql01
我们把容器删了,但是我们本地的数据卷依旧没有丢失,实现容器数据持久化
方式二:通过Docker File 来添加(了解)
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
我们在这里,先体验下,后面我们会详细讲解 DockerFile !
测试:
vim dockerfile1
FROM centos
VOLUME ["/dataVolume1","/dataVolume2"]
CMD echo "-------end------"
CMD /bin/bash
cat dockerfile1
docker build -f /home/docker-test-volume/dockerfile1 -t lxw/centos .
上图的每一个命令就是镜像的一层
启动容器
docker run -it 0e97e1891a3d /bin/bash
问题:通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?
我们没有设置目录,所以之前是匿名挂载。
# 容器内创建文件
cd dataVolume1
touch test01
# 宿主机
docker ps
docker inspect f221db53d413
# 找到了路径
# 查看文件是否同步出去了
5.3、匿名和具名挂载
匿名挂载
# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 匿名挂载的缺点,就是不好维护,通常使用命令 docker volume维护
docker volume ls
这种就是匿名挂载,-v的时候只有容器内的路径,没有容器外的路径
具名挂载
-v 卷名:/容器内路径
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
# 查看挂载的路径
docker volume inspect nginxconfig
所有docker容器内分卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data
我们通过具名挂载可以很方便的找到我们的一个卷
如何确定是具名挂载还是匿名挂载
-v 容器内路径 # 匿名挂载 默认路径和具名挂载相同,但是名字不好辨认
-v 卷名:容器内路径 # 具名挂载 默认存在主机路径的/var/lib/docker/volumes/xxxx/_data
-v /宿主机路径::容器内路径 # 指定路径挂载
改变文件的读写权限
# 改变文件的读写权限
# ro: readonly 只读
# rw: readwrite 可读可写 默认为rw权限
# 指定容器对我们挂载出来的内容的读写权限
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx
# 只要看到ro就说明这个路径只能通过宿主机来操作,docker容器权限为只读
5.4、初识Dockerfile
挂载数据卷的方式二:容器外使用dockerfile来创建build镜像的时候就指定数据卷
创建dockerfile1文件,内容为:
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
构建build
:
docker build -f ./dockerfile1 -t lxw/centos:0.1 .
查看docker images
:
启动我们的自己生成的centos
docker run -it 3c611fec9132 /bin/bash
可以看到我们生成镜像的时候自动挂载的,数据卷目录volume01,volume02(是匿名挂载)
在容器内数据卷volume01创建文件cantainer.txt
cd volume01
touch cantainer.txt
查看容器信息,找到数据卷挂载路径
docker ps
docker inspect ea32e04237b8
既然是匿名挂载,找到数据卷挂载对应的的外部路径
来到外部路径,查看刚才在容器内创建的cantainer.txt
cd /var/lib/docker/volumes/036800d80d4c98d74f9bd8fb1f9dc444d42f2b8283088078ea6e8a1c56ae9ad5/_data
ls
存在cantainer.txt,挂载成功。
这种方式我们未来使用非常多,因为我们通常会自己构建镜像。(如果没有创建时挂载,就需要容器内手动挂载 -v 卷名:容器内路径)
5.5、数据卷容器
需求:两个/多个mysql同步共享数据
启动三个容器容器。
1.启动docker01
docker run -it --name docker01 lxw/centos:0.1
ctrl+p+q #退出容器,但不停止容器
2.启动docker02,同时挂载docker02与docker01同步
共享数据。类似继承关系,docker02继承了docker01的数据卷,docker01就是数据卷容器。
docker run -it --name docker02 --volumes-from docker01 lxw/centos:0.1
3.验证docker02与docker01是否同步:
在docker01的volume01下创建docker01.txt
docker attach b15967131d9d
cd volume01
touch docker01.txt
来到docker02中查看,存在docker01.txt
4.创建docker03,也继承docker01
docker run -it --name docker02 --volumes-from docker01 lxw/centos:0.1
发现文件依然同步存在
在docker03中的volume01中创建新文件,观察发现,docker01和docekr02中会同步。
结论:三者voluem文件同步共享
5.停止并删除docker01,测试docker02和dcoker03是否还会共享(docker02与docker03继承自docker01)
exit
docker ps # 已经停掉,只剩docker02和docker03
docker ps -a # 查找docker01容器
docker rm -f b15967131d9d # 删除docker01容器
docker ps -a # docker01容器彻底没有了
删除docker01后在docker02和docker03中再次查看volume01中的文件,发现仍然存在,继续在docerk02创建,发现docker03仍会同步。
结论:删除docker01后,docker02和docker03仍会共享。
原理:三者之间是一个拷贝的概念,继承后就会相互拷贝
6.实现mysql共享数据
docker run -d -p 3500:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d -p 3501:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
# 实现两个mysql同步数据
这里有问题:
实测mysql不能这么挂载同步,mysql具有引擎id,不能多个mysql读取同一个目录文件,思路最重要。
6、DockerFile
6.1、DockerFile介绍
dockerfile 是用来构建docker镜像的文件,是一个命令参数脚本
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像
我们看看centos的包,点击去,发现是github链接
从github上我们看到,其实就是一个dockerfile文件,内部代码也很简单
6.2、DockerFile构建过程
基础知识:
1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下,顺序执行
3、# 表示注释
4、每条指令都会创建一个新的镜像层,并对镜像进行提交
流程:
1、docker从基础镜像运行一个容器
2、执行一条指令并对容器做出修改
3、执行类似 docker commit 的操作提交一个新的镜像层
4、Docker再基于刚提交的镜像运行一个新容器
5、执行dockerfile中的下一条指令直到所有指令都执行完成!
dockerfile是面向开发的,我们以后要发布项目,做镜像,就要编写dockerfile文件。
docker镜像目前逐渐成为企业交付的标准,必须要掌握。
-
dockerfile:构建文件,定义了一切的步骤,源代码
-
dcokerimages:通过dockerfile构建生成的镜像,就是最终发布和运行的产品,原来是jar/war包
-
docker容器:容器就是镜像运行起来提供服务的
6.3、DockerFile指令
FROM # 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER # 镜像维护者信息,姓名+邮箱
RUN # 容器构建时需要运行的命令
EXPOSE # 当前容器对外保留出的端口
WORKDIR # 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV # 用来在构建镜像过程中设置环境变量
ADD # 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY # 类似ADD,拷贝文件和目录到镜像中!
VOLUME # 容器数据卷,用于数据保存和持久化工作
CMD # 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT # 指定一个容器启动时要运行的命令!和CMD一样
ONBUILD # 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发
6.4、实战测试
Docker Hub 中99% 的镜像都是通过在base镜像(Scratch)中安装和配置需要的软件构建出来的
1、自定义一个 centos
1.编写dockerfile文件
FROM centos
MAINTAINER lxw<1211304872@qq.com>
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
2.构建一个镜像
docker build -f mydockerfile-centos -t mycentos:0.1 .
3.测试运行(我们的centos安装了vim ,net-tools,增加了工作目录/usr/local)
与原来的centos对比:
4.镜像的变更历史
docker history mycentos:0.1
我们查看一下tomcat的history(果然不出所料的有一行暴露了8080端口)
2、CMD 和 ENTRYPOINT 的区别
CMD # 指定一个容器启动时要运行的命令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!
ENTRYPOINT # 指定一个容器启动时要运行的命令!和CMD一样,docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!
CMD:
1.创建dockerfile并build并启动
FROM centos
CMD ["ls","-a"]
2.启动cmdtest之后:发现ls -a
命令生效了
3.刚才ls -a
执行了,我们想执行ls -al
,直接后缀-l
不行,我们只能输入ls -al
完整命令,因为CMD会替换掉原先内容。
ENTRYPOINT命令
1.新建dockerfile-entrypoint-test,并build
2.直接运行,ENTRYPOINT与CMD无差别
3.可以直接追加-l
以实现ls -al
的效果,由此可见,ENTRYPOINT可追加形成组合
3、自定义镜像 tomcat
1、准备镜像文件 tomcat压缩包,jdk的压缩包
2、编写dockerfile文件
FROM centos
MAINTAINER lxw<1211304872@qq.com>
COPY readme.txt /usr/local/cincontainer.txt
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.54.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.54
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.54
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.54/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.54/bin/logs/catalina.out
当前文件状态:
3、构建镜像
docker build -t diytomcat .
4、启动tomcat
docker run -d -p 9090:8080 --name lxw-tomcat -v /lxw/mytomcat/test:/usr/local/apache-tomcat-9.0.54/webapps/test -v /lxw/mytomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.54/logs diytomcat
5、访问测试
curl localhost:9090
然后外网也能访问:
6、发布项目,我们在本地test目录创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>这是一个test</h1>
</body>
</html>
然后由于我们挂载了容器内的test目录,所以我们看到webapps/test目录下有index.html文件
然后我们访问8090/test/index.html页面,访问成功
7、查看日志
cd tomcatlogs/
cat catalina.out
日志也可以在主机查看了。
6.5、发布镜像
发布到dockerHub
1、一个可登录的账号
2、登录,提交
# 1.查看登录帮助
docker login --help
# 2.登录
docker login -u badwei11
# 3.提交镜像
docker push badwei11/diytomcat:1.0
# 注意,这里的作者要和注册账号一致,否则会被拒绝
# 所以我们要先重新tag一个镜像,然后再执行上述代码
docker tag 1cdc642f551f badwei11/diytomcat:1.0
上传完成
我们去官网看看
发布到阿里云镜像服务
1、登录阿里云,找到容器镜像服务
2、创建命名空间
3、创建镜像仓库,选择本地仓库
4、浏览信息
操作步骤(官网很全):
docker login --username=youwei233x registry.cn-hangzhou.aliyuncs.com
docker tag 1cdc642f551f registry.cn-hangzhou.aliyuncs.com/badwei11/badwei11-test:1.0
docker push registry.cn-hangzhou.aliyuncs.com/badwei11/badwei11-test:1.0
上传完成
6.6、总结
7、Docker 网络
7.1、理解Docker0
准备工作:清空所有的容器,清空所有的镜像
docker rm -f $(docker ps -a -q) # 删除所有容器
docker rmi -f $(docker images -qa) # 删除全部镜像
我们先来做个测试
ip addr
lo 127.0.0.1 # 本机回环地址
eth0 172.17.90.138 # 阿里云的私有IP(内网)
docker0 172.18.0.1 # docker网桥
# 问题:Docker 是如何处理容器网络访问的?
docker run -it -P --name tomcat01 tomcat /bin/bash
# docker exec -it tomcat01 ip addr
# 容器内没有ip addr这个命令,进容器装一个就行了
apt update && apt install -y iproute2
ip addr # 或者在容器外docker exec -it tomcat01 ip addr
我们发现得到了一个eth0@if59这么一个地址,是docker分配的,那我们的主机能不能ping通这个地址呢?
ping 172.18.0.2
发现linux主机可以ping通docker容器内部
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,j就会有docker0,这是个桥接网卡,使用了veth-pair技术
再次测试ip addr
,发现多了一个59: vethd61a30a@if58
我们再启动一个docker容器
docker run -d -P --name tomcat02 tomcat
ip addr
我们发现容器带来的网卡都是一对一对的。
比如上面的tomcat01:58-59
veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
测试tomcat01和 tomcat02依旧可以ping通
我们来画一个网络模型图
结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
7.2、--Link
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?
jdbc:mysql://mysql:3306
,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link的操作!
docker run -d -p 3500:8080 --name tomcat01 tomcat
docker run -d -p 3501:8080 --name tomcat02 tomcat
# 直接后缀/bin/bash 进入tomcat
# 下面进入也可以,ctrl+p+q退出不停止
docker exec -it 1536ea5fb233 /bin/bash
cp -r webapps.dist/* webapps
# 没有ip命令,装一个
apt update && apt install -y iproute2
# 没有ping,安装一个
apt-get update
apt-get install inetutils-ping
# 在tomcat01 ping一下tomcat02
ping tomcat02
# 发现ping不通
#启动tomcat03,连接tomcat02
docker run -d -p 3502:8080 --name tomcat03 --link tomcat02 tomcat
docker exec -it ac2a3eded5aa /bin/bash
# 发现tomcat03->tomcat02可以ping通
# 但是tomcat03->tomcat01不能ping通,tomcat02->tomcat03也不能ping通
思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件,发现了tomcat02的地址
反观tomcat02的hosts文件:发现啥都没有,自然反向ping不通
本质:所以这里其实就是配置了一个 hosts 地址而已!
原因:--link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。
--link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式
查看网络
docker network ps
docker network inspect 45cddcdd75be
这是docker0
172.18.0.0/16 这里的16代表255*255,去掉0个255,我们有65534个可以分配的ip
还有tomcat01,tomcat02,tomcat03
docker ps
docker inspect ac2a3eded5aa
我们自定义网络,不使用docker0。
docker0问题:他不支持容器名连接访问
7.3、自定义网络(容器互联)
--link和自定义网络都属于容器互联
基本命令查看
查看所有的docker网络
docker network ls
网络模式
bridge:桥接 docker大桥(默认,自己创建也使用bridge模式)
none:不配置网络
host:和宿主机共享网络
container:容器内网络连同(用的少,局限大)
测试
1、删除原先容器
# 删除原先的容器
docker rm -f $(docker ps -aq)
# 查看ip addr很干净
ip addr
2、接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的
# 默认我们不配置网络,也就相当于默认值 --net bridge 使用的docker0
docker run -d -p 3500:8080 --name tomcat01 --net bridge tomcat
# docker0特点,默认,域名不能访问
3、我们可以让容器创建的时候使用自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
docker network ls
docker network inspect mynet
# 我们来启动两个容器测试,使用自己的 mynet!
docker run -d -p 3500:8080 --name tomcat-net-01 --net mynet tomcat
docker run -d -p 3501:8080 --name tomcat-net-02 --net mynet tomcat
# 再查看mynet
docker network inspect mynet
# 我们现在来ping一下tomcat-net-01->tomcat-net-02
docker exec -it tomcat-net-01 ping tomcat-net-02
# 发现可以ping通
# 发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
# 所以我们平时都可以这样使用网络,不使用--link效果一样,所有东西实时维护好,直接域名 ping通。
7.4、网络连通
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
docker run -d -p 3502:8080 --name tomcat01 tomcat
docker run -d -p 3503:8080 --name tomcat02 tomcat
docker network --help
# 我们来测试一下!打通mynet-docker0
# 命令 docker network connect [OPTIONS] NETWORK CONTAINER
docker network connect mynet tomcat01
docker network inspect mynet
# 发现我们的tomcat01就进来这里了,tomcat01拥有了双ip
docker connect之后就ping通了(tomcat-net-01 ping tomcat01)
7.5、部署一个Redis集群
# 创建网卡
docker network create redis --subnet 172.38.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-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个容器
docker run -p 637${port}:6379 -p 1637${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 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
# 三
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.38.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.38.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.38.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.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 进入一个redis,注意这里是 sh命令
docker exec -it redis-1 /bin/sh
# 创建集群
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-cli -c
# 查看集群信息
cluster info
# 查看节点
cluster nodes
# set a b
# 停止到存值的容器
# 然后再次get a,发现依旧可以获取值
# 查看节点,发现高可用完全没问题
创建集群
连接集群,查看集群信息,查看节点
停止存入的master,发现slave自动成为master,并且数据可查
8、IEDA整合Docker
IDEA可以安装docker插件,可能最新版的IDEA直接默认安装了docker插件,不需要自己安装了
1、构架springboot项目
写一个helloController的测试
@Controller
public class HelloWord {
@RequestMapping("/hello")
@ResponseBody
public String helloWorld(){
return "hello world!!!";
}
}
2、打包应用
maven->package
打包完成后,我们运行jar包测试一下
3、编写dockerfile
FROM java:8
# 服务器只有dockerfile和jar在同级目录
COPY *.jar /app.jar
CMD ["--server.port=3500"]
# 指定容器内要暴露的端口
EXPOSE 3500
ENTRYPOINT ["java","-jar","/app.jar"]
4、构建镜像
将Dockerfile 和 项目的 jar 包上传到linux服务器上,构建运行
docker build spring-docker .
查看docker镜像images
5、发布运行
docker run -d -p 3500:3500 --name spring-docker-01 spring-docker
内部访问成功,我们试试外部访问3500/hello,成功!
9、Docker Compose
9.1、简介
Docker
DockerFile build run 手动操作,单个容器!
微服务。100个微服务!依赖关系。
Docker Compose 来轻松高效的管理容器i。定义运行多个容器。
官方文档:https://docs.docker.com/compose/
Using Compose is basically a three-step process:
- Define your app’s environment with a
Dockerfile
so it can be reproduced anywhere.
Dockerfile 保证我们的项目在任何地方可以运行。 - Define the services that make up your app in
docker-compose.yml
so they can be run
together in an isolated environment.
services 什么是服务。
docker-compose.yml 这个文件怎么写! - Run
docker-compose up
and Compose starts and runs your entire app.
启动项目
作用:批量容器编排。
理解
官方文档
Compose 是Docker官方的开源项目。需要安装!
Dockerfile 让程序在任何地方运行。 web服务。 redis、mysql、nginx ... 多个容器。 run Compose
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
Compose :重要的概念。
服务services, 容器。应用。(web、redis、mysql....)
项目project。 一组关联的容器。 博客。web、mysql。
评论区