这个笔记是狂神说的docker基础篇视频的对应的笔记:https://www.bilibili.com/video/BV1og4y1q7M4
进阶视频:https://www.bilibili.com/video/BV1kv411q7Qc
转载链接:Oddfar Note ;有一说一,他们的博客是真滴好看
也可参考:https://www.pdai.tech/md/devops/docker/docker-01-docker-vm.html
我们使用的是 CentOS 7 (64-bit)
Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
查看自己的内核:
用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型 等)。
uname -r
查看版本信息:
cat /etc/os-release
官网安装参考手册:https://docs.docker.com/engine/install/centos/
yum安装gcc相关环境(需要确保虚拟机可以上外网 )
yum -y install gcc
yum -y install gcc-c++
卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装需要的软件包
sudo yum install -y yum-utils
设置镜像仓库
官网(国外):
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
阿里云(推荐):
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum软件包索引
yum makecache fast
安装 Docker CE
yum install docker-ce docker-ce-cli containerd.io
启动 Docker
systemctl start docker
至此,已经安装完
查看版本
docker version
查看安装的镜像
docker images
测试运行hello
docker run hello-world
卸载docker
systemctl stop docker
yum -y remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
介绍:https://www.aliyun.com/product/acr
查看自己的镜像加速器并配置
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://cbl6xdl3.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
测试 HelloWorld
启动hello-world
docker run hello-world
run干了什么?
docker version # 显示 Docker 版本信息。
docker info # 显示 Docker 系统信息,包括镜像和容器数。
docker --help # 帮助
列出本地主机上的镜像
解释:
同一个仓库源可以有多个 TAG,代表这个仓库源的不同版本,我们使用 REPOSITORY:TAG
定义不同的镜像,如果你不定义镜像的标签版本,docker将默认使用 latest 镜像!
搜索镜像:
docker search 某个镜像的名称 对应DockerHub仓库中的镜像
docker search mysql
可选项:
列出收藏数不小于指定值的镜像,例如
docker search mysql --filter=stars=1000
也通过Docker Hub 进行查找
比如https://hub.docker.com/search?q=mysql&type=image
下载镜像
不写tag,默认是latest
docker pull mysql
指定版本下载
docker pull mysql:5.7
删除镜像
docker rmi -f 镜像id # 删除单个
docker rmi -f 镜像名:tag 镜像名:tag # 删除多个
删除全部
docker rmi -f $(docker images -qa)
有镜像才能创建容器,我们这里使用 centos 的镜像来测试,就是虚拟一个 centos !
docker pull centos
docker run [OPTIONS] IMAGE [COMMAND][ARG...]
常用参数说明
参数 | 说明 |
---|---|
–name=“Name” | 给容器指定一个名字 之后再对容器操作,可以用这个name,相当于“别名” |
-d |
后台方式运行容器,并返回容器的id! |
-i |
以交互模式运行容器,通过和 -t 一起使用 |
-t |
给容器重新分配一个终端,通常和 -i 一起使用 |
-P | 随机端口映射(大写) |
-p | 指定端口映射(小写),一般可以有四种写法 |
-p 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
查看镜像:
启动一个容器,使用centos进行用交互模式启动容器,在容器内执行/bin/bash
命令!
docker run -it centos /bin/bash
退出容器:
docker ps [OPTIONS]
常用参数说明
参数 | 说明 |
---|---|
-a | 列出当前所有正在运行的容器 + 历史运行过的容器 |
-l | 显示最近创建的容器 |
-n=? | 显示最近n个创建的容器 |
-q | 静默模式,只显示容器编号。 |
指令 | 说明 |
---|---|
exit | 容器停止退出 |
ctrl+P+Q | 容器不停止退出 |
指令 | 说明 |
---|---|
docker start (容器id or 容器名) | 启动容器 |
docker restart (容器id or 容器名) | 重启容器 |
docker stop (容器id or 容器名) | 停止容器 |
docker kill (容器id or 容器名) | 强制停止容器 |
指令 | 说明 |
---|---|
docker rm 容器id | 删除指定容器,不能删除正在运行的容器,如果要强制删除使用rm -f |
docker rm -f $(docker ps -a -q) | 删除所有容器 |
docker ps -a -q | xargs docker rm | 删除所有容器 |
docker start id/name
启动之前停止关闭的容器
docker run -d 容器名
启动centos,使用后台方式启动,例如:
docker run -d centos
问题: 使用docker ps
查看,发现容器已经退出了!
解释:Docker容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命令,就会自动退出。
比如,你运行了nginx服务,但是docker前台没有运行应用,这种情况下,容器启动后,会立即自杀,因为他觉得没有程序了,所以最好的情况是,将你的应用使用前台进程的方式运行启动。
清理停止的容器:
docker container prune
docker logs -f -t --tail 容器id
例子:我们启动 centos,并编写一段脚本来测试玩玩!最后查看日志
docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"
查看日志:
docker logs 容器id
参数 | 说明 |
---|---|
-t | 显示时间戳 |
-f | 打印最新的日志 |
–tail | 数字显示多少条! |
docker logs -tf --tail 10 87f5e5a2954e
docker stop 87f5e5a2954e
docker top 容器id
docker inspect 容器id
命令一:
docker exec -it 容器id bashShell
例如:
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@VM-0-6-centos ~]# docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"
a9b967bdbc870bb039b69c76ddc3d3ce6aa87d57c51a8040e32224fb45576b28
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9b967bdbc87 centos "/bin/sh -c 'while t…" 8 seconds ago Up 7 seconds upbeat_haibt
[root@VM-0-6-centos ~]# docker exec -it a9b967bdbc87 /bin/bash
[root@a9b967bdbc87 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:01 ? 00:00:00 /bin/sh -c while true;do echo hello;sleep 1;done
root 37 0 0 10:02 pts/0 00:00:00 /bin/bash
root 59 1 0 10:02 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root 60 37 0 10:02 pts/0 00:00:00 ps -ef
退出容器终端,不会导致容器的停止
[root@a9b967bdbc87 /]# exit
exit
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9b967bdbc87 centos "/bin/sh -c 'while t…" 7 minutes ago Up 7 minutes upbeat_haibt
命令二:
docker attach 容器id
测试:
[root@VM-0-6-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 months ago 13.3kB
centos latest 300e315adb2f 5 months ago 209MB
[root@VM-0-6-centos ~]# docker run -it -d centos /bin/bash
7f9ead6f906b3c691d29866236414e1808d194462ed0839c8ee5c947d731ed57
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f9ead6f906b centos "/bin/bash" 10 seconds ago Up 9 seconds nervous_mcclintock
[root@VM-0-6-centos ~]# docker attach 7f9ead6f906b
[root@7f9ead6f906b /]# echo "hello"
hello
[root@7f9ead6f906b /]# exit
exit
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@VM-0-6-centos ~]#
区别 :
推荐大家使用 docker exec
命令
docker cp 容器id:容器内路径 目的主机路径
例如:将容器中的f1文件拷贝出到 虚拟机的/home目录
docker cp 7f9ead6f906b:/home/f1 /home
命令 | 官方说明 | 解释 |
---|---|---|
attach | Attach local standard input, output, and error streams to a running container | 当前 shell 下 attach 连接指定运行镜像 |
build | Build an image from a Dockerfile | 通过 Dockerfile 定制镜像 |
commit | Create a new image from a container’s changes | 提交当前容器为新的镜像 |
cp | Copy files/folders between a container and the local filesystem | 从容器中拷贝指定文件或者目录到宿主机中 |
create | Create a new container | 创建一个新的容器,同 run,但不启动容器 |
diff | Inspect changes to files or directories on a container’s filesystem | 查看 docker 容器变化 |
events | Get real time events from the server | 从 docker 服务获取容 器实时事件 |
exec | Run a command in a running container | 在已存在的容器上运行命令 |
export | Export a container’s filesystem as a tar archive | 导出容器的内 容流作为一个 tar 归档文件[对应 import ] |
history | Show the history of an image | 展示一个镜像形成历史 |
images | List images | 列出系统当前镜像 |
import | Import the contents from a tarball to create a filesystem image | 从 tar包中的内容创建一个新的文件系统映像[对应export] |
info | Display system-wide information | 显示系统相关信息 |
inspect | Return low-level information on Docker objects | 查看容器详细信息 |
kill | Kill one or more running containers | 杀掉 指定 docker 容器 |
load | Load an image from a tar archive or STDIN | 从一个 tar 包中加载一 个镜像[对应 save] |
login | Log in to a Docker registry | 登陆一个 docker 源服务器 |
logout | Log out from a Docker registry | 从当前 Docker registry 退出 |
logs | Fetch the logs of a container | 输出当前容器日志信息 |
pause | Pause all processes within one or more containers | 暂停容器 |
port | List port mappings or a specific mapping for the container | 查看映射端口对应的容器内部源端口 |
ps | List containers | 列出容器列表 |
pull | Pull an image or a repository from a registry | 从docker镜像源服务器拉取指定镜像或者库镜像 |
push | Push an image or a repository to a registry | 推送指定镜像或者库镜像至docker源服务器 |
rename | Rename a container | 给一个容器改名 |
restart | Restart one or more containers | 重启运行的容器 |
rm | Remove one or more containers | 移除一个或者多个容器 |
rmi | Remove one or more images | 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除] |
run | Run a command in a new container | 创建一个新的容器并运行 一个命令 |
save | Save one or more images to a tar archive (streamed to STDOUT by default) | 保存一个镜像为一个 tar 包[对应 load] |
search | Search the Docker Hub for images | 在 docker hub 中搜 索镜像 |
start | Start one or more stopped containers | 启动容器 |
stats | Display a live stream of container(s) resource usage statistics | 显示容器资源使用统计信息的实时信息 |
stop | Stop one or more running containers | 停止容器 |
tag | Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE | 给源中镜像打标签 |
top | Display the running processes of a container | 查看容器中运行的进程信 息 |
unpause | Unpause all processes within one or more containers | 取消暂停容器 |
update | Update configuration of one or more containers | 更新容器配置 |
version | Show the Docker version information | 查看 docker 版本号 |
wait | Block until one or more containers stop, then print their exit codes | 截取容器停止时的退出状态值 |
拉取镜像:
$ docker pull nginx
-d
后台启动
firewall-cmd --zone=public --add-port=3500/tcp --permanent
firewall-cmd --reload
docker run -d --name mynginx -p 3500:80 nginx
本机测试:curl localhost:3500
进入容器:
[root@VM-0-6-centos ~]# docker exec -it mynginx /bin/bash
# 寻找nginx
root@511741b161de:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@511741b161de:/# cd /usr/share/nginx
root@511741b161de:/usr/share/nginx# ls
html
root@511741b161de:/usr/share/nginx# cd html
root@511741b161de:/usr/share/nginx/html# ls
50x.html index.html
#可看到之前访问的内容是 index.html
root@511741b161de:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
在 docker hub 官网搜索 tomcat:https://hub.docker.com/_/tomcat
翻到下面有教程
docker run -it --rm tomcat:9.0 # 仅测试使用:关闭之后使用docker ps 找不到
1、下载tomcat镜像:
docker pull tomcat
2、启动
docker run -d -p 8080:8080 --name tomcat9 tomcat
3、进入tomcat
docker exec -it tomcat9 /bin/bash
进入后发现,webapps 里什么也没有,默认是最小的镜像,所有不必要的剔除。
root@a1801a340333:/usr/local/tomcat# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist work
root@a1801a340333:/usr/local/tomcat# cd webapps
root@a1801a340333:/usr/local/tomcat/webapps# ls
root@a1801a340333:/usr/local/tomcat/webapps#
若部署一个 jsp 网站,需要把文件复制到容器里,非常麻烦。
我们可以通过“数据卷”技术,将容器内文件和我们 Linux 文件进行映射挂载。
官网:https://hub.docker.com/_/elasticsearch
1、启动:
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
2、查看状态
docker stats 容器id
查看容器的cpu内存和网络状态
查看下cpu状态 ,发现占用的很大
3、增加上内存限制启动
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
启动时,报错:名字已经存在
可通过指令删除
docker rm elasticsearch
我们可通过 docker ps -a
显示所有容器信息
再次启动后,发现内存变小了
访问成功:
[root@VM-0-6-centos ~]# curl localhost:9200
{
"name" : "d49fb1463f0a",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "ycGNdXS0TpC2lcOfIFlPkQ",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
关于名字的作用:
以后我们想启动上次配置的 ElasticSearch,用 docker start 容器名字
即可,不需要在重新配置
[root@VM-0-6-centos ~]# docker start elasticsearch
elasticsearch
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d49fb1463f0a elasticsearch:7.6.2 "/usr/local/bin/dock…" About an hour ago Up 5 seconds 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp elasticsearch
[root@VM-0-6-centos ~] #
如果我们要使用 kibana , 如果配置连接上我们的es呢?网络该如何配置呢?
Portainer
(Rancher)是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷 的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和 服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。
如果仅有一个docker宿主机,则可使用单机版运行,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
首次加载比较慢,且登陆需要注册用户,给admin用户设置密码:
单机版这里选择local即可,选择完毕,点击Connect即可连接到本地docker:
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含 运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
UnionFS (联合文件系统)
UnionFS 是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
典型的Linux文件系统由bootfs和rootfs两部分组成
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这里才200M?
对于一个精简的系统,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就可以了。由此可见对于不同的 linux 发行版, bootfs 基本是一 致的, rootfs 会有差别, 因此不同的发行版可以公用 bootfs。
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
为什么Docker镜像要采用这种分层的结构呢?
最大的好处,莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect
命令!
docker image inspect tomcat:latest
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了 一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统 一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点:
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
docker commit 从容器创建一个新的镜像。
语法:
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
测试
1、从Docker Hub 下载 tomcat 镜像到本地并运行
-it 交互终端 -p 端口映射
docker run -it -p 8080:8080 tomcat
2、访问地址
docker启动官方tomcat镜像的容器,发现404是因为使用了加速器,而加速器里的 tomcat的webapps下没有root等文件!
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a8b6aff64fa3 tomcat "catalina.sh run" 8 minutes ago Up 8 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp silly_feynman
[root@VM-0-6-centos ~]# docker exec -it a8b6aff64fa3 /bin/bash
root@a8b6aff64fa3:/usr/local/tomcat# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist work
进入 tomcat 查看 cd 到 webapps 下发现全部空的,反而有个 webapps.dist 里有对应文件
root@a8b6aff64fa3:/usr/local/tomcat# cd webapps.dist
root@a8b6aff64fa3:/usr/local/tomcat/webapps.dist# ls
ROOT docs examples host-manager manager
我们可以 cp -r
复制文件到webapps下!
root@a8b6aff64fa3:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@a8b6aff64fa3:/usr/local/tomcat# cd webapps
root@a8b6aff64fa3:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
此时再次访问,则不是404
**3、提交修改后的镜像为 tomcat02 **
下次则可以直接启动这个
注意:commit的时候,容器的名字不能有大写,否则报错:invalid reference format
[root@VM-0-6-centos ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a8b6aff64fa3 tomcat "catalina.sh run" 16 minutes ago Up 16 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp silly_feynman
##提交镜像
[root@VM-0-6-centos ~]# docker commit -a="zhiyuan" -m="new tomcat" a8b6aff64fa3 tomcat02:1.1
sha256:620813976effbc8a7e36398a9b801891d1654dea37a50927b36a950ffe21a63b
[root@VM-0-6-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.1 620813976eff 8 seconds ago 672MB
停止后再启动看看,首页可访问
[root@VM-0-6-centos ~]# docker stop a8b6aff64fa3
a8b6aff64fa3
[root@VM-0-6-centos ~]# docker run -it -p 8080:8080 tomcat02:1.1
注册dockerhub https://hub.docker.com/signup
1、登录
docker login -u oddfar
2、将镜像发布出去
[root@VM-0-6-centos logs]# docker push hello-world
Using default tag: latest
The push refers to repository [docker.io/library/hello-world]
f22b99068db9: Layer already exists
errors:
denied: requested access to the resource is denied
unauthorized: authentication required
错误:请求的资源访问被拒绝
问题:本地镜像名无帐号信息,解决加 tag 即可
[root@VM-0-6-centos logs]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 3 months ago 13.3kB
[root@VM-0-6-centos logs]# docker tag d1165f221234 oddfar(用户名)/hello-world(镜像名):1.08(标签)
oddfar 是我的用户名
3、再次push
[root@VM-0-6-centos logs]# docker push oddfar/hello-world:1.0
访问:https://hub.docker.com/ 可看到提交的镜像
登录阿里云 -> 找到容器镜像服务 -> 创建命名空间 -> 创建镜像仓库
点击进入这个镜像仓库,可以看到所有的信息
测试:推送 hello-world
[root@VM-0-6-centos ~]# docker login --username=a_zhiyuan registry.cn-hangzhou.aliyuncs.com
[root@VM-0-6-centos ~]# docker tag d1165f221234 registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0
[root@VM-0-6-centos ~]# docker push registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0
提交成功
数据卷(Data Volume)
docker的理念回顾:
将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够 持久化的!
就好比,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!
所以我们希望容器之间有可能可以共享数据,Docker容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行不通的!
为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除而丢失了!
作用:
卷就是目录或者文件,存在一个或者多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷。
特点:
一句话: 就是容器的持久化,以及容器间的继承和数据共享!
方式一:容器中直接使用命令来添加
在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里。
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
测试:
docker run -it -v /home/d-test:/home centos /bin/bash
查看数据卷是否挂载成功 docker inspect
容器id
[root@VM-0-6-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05fa819084c9 centos "/bin/bash" 20 seconds ago Up 20 seconds friendly_keller
[root@VM-0-6-centos ~]# docker inspect 05fa819084c9
容器:
[root@05fa819084c9 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run s
[root@05fa819084c9 /]# cd home
[root@05fa819084c9 home]# ls
[root@05fa819084c9 home]# touch test.java
主机:
[root@VM-0-6-centos ~]# cd /home/d-test
[root@VM-0-6-centos d-test]# ls
test.java
主机:
[root@VM-0-6-centos d-test]# ls
test.java
[root@VM-0-6-centos d-test]# touch new.java
[root@VM-0-6-centos d-test]# ls
new.java test.java
容器:
docker ps -a
查看所有容器
[root@VM-0-6-centos home]# docker start 05fa819084c9
05fa819084c9
[root@VM-0-6-centos home]# docker attach 05fa819084c9
[root@05fa819084c9 /]# cd /home
[root@05fa819084c9 home]# ls
new.java test.java
安装 mysql 测试
1、安装
docker pull mysql:5.7
2、启动容器 ,-e 为环境变量
mysql 的数据不应该放在容器内,应放主机内!先体验下 -v 挂载卷!
参考官方文档
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=123456 --name mysql01 mysql:5.7
连接 mysql 并创建一个数据库
[root@VM-0-6-centos data]# mysql -h 127.0.0.1 -P 3310 -u root -p
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
方式二:通过Docker File 来添加
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
这里先了解体验一下,后面有详细介绍
1、编写DockerFile文件
我们在宿主机 /home 目录下新建一个 docker-test-volume文件夹
mkdir docker-test-volume
出于可移植和分享的考虑,之前使用的 -v 主机目录:容器目录
这种方式不能够直接在 DockerFile 中实现。
[root@VM-0-6-centos docker-test-volume]# pwd
/home/docker-test-volume
[root@VM-0-6-centos docker-test-volume]# vim dockerfile1
[root@VM-0-6-centos docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "-------end------"
CMD /bin/bash
说明:在编写DockerFile文件中使用 VOLUME 来给镜像添加一个或多个数据卷
2、build生成镜像
build生成镜像,获得一个新镜像 test-centos,注意最后面有个 .
-f
是指定的dockerFile文件位置;-t
是生成的镜像名称
docker build -f /home/docker-test-volume/dockerfile1 -t test-centos .
然后启动容器:
docker run -it test-centos /bin/bash
通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?
3、查看数据目录
我们在数据卷中新建一个文件
[root@93343e21a67b /]# cd dataVolumeContainer1
[root@93343e21a67b dataVolumeContainer1]# touch container.txt
查看下这个容器的信息
docker inspect 93343e21a67b
可以看到挂载的路径
在主机目录里看到之前在容器里创建的文件
[root@VM-0-6-centos ~]# cd /var/lib/docker/volumes/7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788/_data
[root@VM-0-6-centos _data]# ls
container.txt
注意:如果访问出现了 cannot open directory: Permission denied
解决办法:在挂载目录后多加一个 --privileged=true参数即可
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
可通过命令 docker volume ls
查看挂载的列表
[root@VM-0-6-centos ~]# docker volume ls
DRIVER VOLUME NAME
local 4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local 7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local 7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52
这些没指定名字的都是匿名挂载,我们 -v 只写了容器内路径,并没写容器外路径
挂载目录是: /var/lib /docker/volumes/VOLUME-NAME/_data
匿名挂载的缺点,就是不好维护,不清楚目录挂载的是哪个容器
-v 卷名:/容器内路径
例如取名为 juming 来挂载
[root@VM-0-6-centos ~]# docker run -d -P --name nginx02 -v juming:/etc/nginx nginx
112f36599f077eada56197c22dd3b3a3eaba2e5bb38bf2cb19adc783163991e7
[root@VM-0-6-centos ~]# docker volume ls
DRIVER VOLUME NAME
local 4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local 7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local 7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52
local juming #(卷名是juming,目录是/etc/nginx)
查看挂载的目录:docker volume VOLUME-NAME
[root@VM-0-6-centos ~]# docker volume inspect juming
[
{
"CreatedAt": "2021-06-05T16:32:10+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming/_data",
"Name": "juming",
"Options": null,
"Scope": "local"
}
]
挂载操作中,没指定目录名情况下,默认在 /var/lib/docker/volumes/
目录下
指定容器对我们挂载出来的内容的读写权限
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: readonly 只读
rw: readwrite 可读可写
之前的是主机和容器之间共享数据,那么如何实现容器和容器之间的共享数据呢?
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享 --volumes-from
,挂载数据卷的容器,称之为数据卷容器(Data Volume Container)
测试容器间传递共享
使用之前的镜像:test-centos
为模板,运行容器 docker01(父容器),docker02,docker03
他们都会具有容器卷 /dataVolumeContainer1
和 /dataVolumeContainer2
1、先启动一个父容器docker01,然后在 dataVolumeContainer2 新增文件
[root@VM-0-6-centos _data]# docker run -it --name docker01 test-centos
[root@cd87cb3eb33b /]# ls -l
total 56
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Jun 5 08:56 dataVolumeContainer1
drwxr-xr-x 2 root root 4096 Jun 5 08:56 dataVolumeContainer2
............
[root@cd87cb3eb33b /]# cd dataVolumeContainer2
[root@cd87cb3eb33b dataVolumeContainer2]# touch docker01.txt
退出且不停止容器运行:ctrl+P+Q
2、创建docker02,docker03 让他们继承docker01
可以看到 docker01 创建的文件存在
[root@VM-0-6-centos _data]# docker run -it --name docker02 --volumes-from docker01 test-centos
[root@f81238516f65 /]# cd dataVolumeContainer2
[root@f81238516f65 dataVolumeContainer2]# ls
docker01.txt
[root@f81238516f65 dataVolumeContainer2]# touch docker02.txt
[root@VM-0-6-centos _data]# docker run -it --name docker03 --volumes-from docker01 test-centos
[root@c8c41a2a0831 /]# ls
bin dataVolumeContainer1 dataVolumeContainer2 dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@c8c41a2a0831 /]# cd dataVolumeContainer2
[root@c8c41a2a0831 dataVolumeContainer2]# ls
docker01.txt docker02.txt
3、回到docker01发现可以看到 02 和 03 添加的共享文件
[root@VM-0-6-centos ~]# docker attach docker01
[root@cd87cb3eb33b dataVolumeContainer2]# ls -l
total 0
-rw-r--r-- 1 root root 0 Jun 5 08:56 docker01.txt
-rw-r--r-- 1 root root 0 Jun 5 08:58 docker02.txt
-rw-r--r-- 1 root root 0 Jun 5 09:00 docker03.txt
删除 docker01 后 ,docker02 修改文件后, docker03 还可以正常共享数据
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。 存储在本机的文件则会一直保留!
大家想想,Nginx,tomcat,mysql 这些镜像都是哪里来的?官方能写,我们不能写吗?
我们要研究自己如何做一个镜像,而且我们写的微服务项目以及 springboot 打包上云部署,Docker就是最方便的。
微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。
流程:开发应用=>DockerFile=>打包为镜像=>上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动 运行。
还可以方便移植!
dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
构建步骤:
1、编写DockerFile文件
2、docker build 构建镜像
3、docker run
查看之前拉取的 centos :https://hub.docker.com/_/centos
查看Dockerfile
文件
基础知识:
1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下,顺序执行
3、#
表示注释
4、每条指令都会创建一个新的镜像层,并对镜像进行提交
流程:
1、docker从基础镜像运行一个容器
2、执行一条指令并对容器做出修改
3、执行类似 docker commit 的操作提交一个新的镜像层
4、Docker再基于刚提交的镜像运行一个新容器
5、执行dockerfile中的下一条指令直到所有指令都执行完成!
说明:
从应用软件的角度来看,DockerFile,docker镜像 与 docker容器 分别代表软件的三个不同阶段。
DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!
DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容 包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进 程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权 限控制)等等。
Docker镜像:在DockerFile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行 Docker 镜像时,会真正开始提供服务;
Docker容器:容器是直接提供服务的。
关键字 | 说明 |
---|---|
FROM |
基础镜像,当前新镜像是基于哪个镜像的 |
MAINTAINER | 镜像维护者的姓名混合邮箱地址 |
RUN |
容器构建时需要运行的命令 |
EXPOSE |
当前容器对外保留出的端口 |
WORKDIR |
指定在创建容器后,终端默认登录的进来工作目录,一个落脚点 |
ENV | 用来在构建镜像过程中设置环境变量 |
ADD |
将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包 |
COPY | 类似ADD,拷贝文件和目录到镜像中! |
VOLUME |
容器数据卷,用于数据保存和持久化工作 |
CMD | 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效! |
ENTRYPOINT | 指定一个容器启动时要运行的命令!和CMD一样 |
ONBUILD | 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD被触发 |
我们之前说过,两个命令都是指定一个容器启动时要运行的命令
CMD
Dockerfile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!
ENTRYPOINT
docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!
测试 CMD 命令
1、编写文件
[root@VM-0-6-centos dockerfile-test]# vim dockerfile-cmd-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-cmd-test
FROM centos
CMD [ "ls", "-a" ]
2、构建并运行
docker build -f dockerfile-cmd-test -t cmdtest .
docker run cmdtest
3、如果我们希望用 -l 列表展示信息,我们就需要加上 -l参数
[root@VM-0-6-centos dockerfile-test]# docker run cmdtest -l
# 发现报错:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
问题:我们可以看到可执行文件找不到的报错,executable file not found。
之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。
因此这里的 -l
替换了原来的 CMD,而不是添加在原来的 ls -a
后面。
而 -l 根本不是命令,所以自然找不到。
那么如果我们希望加入 -l
这参数,我们就必须重新完整的输入这个命令:
docker run cmdtest ls -al
测试 ENTRYPOINT 命令
1、编写文件
[root@VM-0-6-centos dockerfile-test]# vim dockerfile-entrypoint-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-entrypoint-test
FROM centos
ENTRYPOINT [ "ls", "-a" ]
2、构建并运行
docker build -f dockerfile-entrypoint-test -t entrypointtest .
docker run entrypointtest
3、测试 -l 参数,发现可以直接使用,这里就是一种追加
我们可以明显的知道 CMD 和 ENTRYPOINT 的区别了
docker run entrypointtest -l
官方默认的 CentOS 的情况不支持 vim
和 ifconfig
指令
我们自己构建一个支持这些指令的镜像
1、编写文件
[root@VM-0-6-centos home]# cd dockerfile-test
[root@VM-0-6-centos dockerfile-test]# ls
my-centos
[root@VM-0-6-centos dockerfile-test]# cat my-centos
FROM centos
MAINTAINER zhiyuan<[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
2、构建
命令最后有一个 .
表示当前目录
docker build -f my-centos(文件名) -t mycentos(镜像名):0.1(TAG) .(表示当前目录)
成功后:
3、运行
docker run -it mycentos:1.1
测试后,可以看到,我们自己的新镜像进入之后默认在``/usr/local`并且已经支持 vim 和 ifconfig的命令了
列出镜像的变更历史:
docker history 镜像名\镜像id
步骤:
将 JDK 和 tomcat 安装的压缩包拷贝/home/build
目录下
新建一个 read.txt 文件
新建一个 Dockerfile
文件
[root@VM-0-6-centos home]# cd build
[root@VM-0-6-centos build]# ls
apache-tomcat-9.0.46.tar.gz Dockerfile jdk-8u11-linux-x64.tar.gz read.txt tomcat
Dockerfile 内容
FROM centos
MAINTAINER zhiyuan<[email protected]>
#把宿主机当前上下文的read.txt拷贝到容器/usr/local/路径下
COPY read.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u11-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.46.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#变量
ENV MYPATH /usr/local
#设置工作访问时候的WORKDIR路径,登录落脚点
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.46
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.46/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.46/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/bin/logs/catalina.out
构建镜像:
docker build -t diytomcat .
在此目录下默认构建 Dockerfile
文件,所以不需要带上文件名
启动:
docker run -d -p 9090:8080 --name mydiytomcat -v /home/build/tomcat/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /home/build/tomcat/logs/:/usr/local/apache-tomcat-9.0.46/logs --privileged=true diytomcat
备注:Docker挂载主机目录Docker访问出现cannot open directory Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
写个测试网站扔到test目录:
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<display-name>Testdisplay-name>
web-app>
a.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试title>
head>
<body>
Hello World!<br/>
<% System.out.println("-------my docker tomcat-------");%>
body>
html>
查看日志:
[root@VM-0-6-centos tomcat]# cd logs
[root@VM-0-6-centos logs]# cat catalina.out
1、使用 IDEA 构建一个 SpringBoot 项目
2、编写 Controller
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello,world";
}
}
打包成 jar 包
3、构建镜像
将打包好的 jar 包拷贝到 Dockerfile 同级目录,编写 Dockerfile文件
FROM java:8
# 服务器只有dockerfile和jar在同级目录
COPY *.jar /app.jar
CMD ["--server.port=8080"]
# 指定容器内要暴露的端口
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
构建运行
# 构建镜像
docker build -t idea-ks .
# 运行
docker run -d -P --name idea-ks idea-ks
最后测试访问
查看本地ip ip addr
[root@VM-0-6-centos ~]# ip addr
#lo本机回环地址
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever pr eferred_lft forever
#eth0:阿里云的私有IP
2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:9a:88:4d brd ff:ff:ff:ff:ff:ff
inet 172.17.0.6/20 brd 172.17.15.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe9a:884d/64 scope link
valid_lft forever preferred_lft forever
# docker网桥
3: docker0: mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:d1:ba:72:7a brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:d1ff:feba:727a/64 scope link
valid_lft forever preferred_lft forever
Docker 是如何处理容器网络访问的?
我们之前安装ES的时候,留过一个问题,就是安装Kibana的问题,Kibana得指定ES的地址!或者我们实际场景中,我们开发了很多微服务项目,那些微服务项目都要连接数据库,需要指定数据库的url地址,通过ip。但是我们用Docker管理的话,假设数据库出问题了,我们重新启动运行一个,这个时候数据库的地址就会发生变化,docker会给每个容器都分配一个ip,且容器和容器之间是可以互相访问的。 我们可以测试下容器之间能不能ping通过。
[root@VM-0-6-centos ~]# docker run -d -P --name tomcat01 tomcat
# 查看tomcat01的ip地址,docker会给每个容器都分配一个ip!
[root@VM-0-6-centos ~]# docker exec -it tomcat01 ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
24: eth0@if25: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 ``
valid_lft forever preferred_lft forever
# 虚拟机可以和容器ping通!
[root@VM-0-6-centos ~]# ping 172.18.0.2
原因
每一个安装了 Docker 的 linux 主机都有一个 docker0 的虚拟网卡。这是个桥接网卡,使用了 veth-pair 技术!
再次查看主机的 ip addr
:本来有三个网络,启动tomcat容器之后,会多了一个网络!
每启动一个容器,linux主机就会多了一个虚拟网卡。
#启动一个tomcat01,主机的ip地址多了个 25: veth2b7cb71@if24
#然后我们在tomcat01容器中查看容器的ip 24: eth0@if25
#我们再启动一个tomcat02观察
[root@VM-0-6-centos ~]# docker run -d -P --name tomcat02 tomcat
# 然后发现linux主机上又多了一个网卡 27: veth4d2bd95@if26
# 我们看下tomcat02的容器内ip地址是 26: eth0@if27
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ip addr
可以发现:只要启动一个容器,就有一对网卡。
veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络结构,比如 OpenStack Neutron。
我们来测试下 tomcat01 和 tomcat02 容器间是否可以互相 ping 通
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
所以:容器和容器之间是可以互相访问的。
结论:tomcat1 和 tomcat2 共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是 docker0 网络。 docker 默认会给容器分配一个可用 ip 。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据 Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网 关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接 通信。
Docker 容器网络就很好的利用了 Linux 虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫 veth pair);
Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?
就像 jdbc:mysql://mysql:3306
,这样的话哪怕 mysql 重启,我们也不需要修改配置了!
docker提供了 --link
的操作!
# 我们使用tomcat02,直接通过容器名ping,不使用ip
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat01
# ping 不通
ping: tomcat01: Name or service not known
#我们再启动一个tomcat03,但是启动的时候连接tomcat02
[root@VM-0-6-centos ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91
#这个时候,我们就可以使用tomcat03 ping通 tomcat02 了
[root@VM-0-6-centos ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.092 ms
# tomcat3 ping不通 tomcat1
[root@VM-0-6-centos ~]# docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known
# tomcat2 ping不通 tomcat3 反向也ping不通
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
这是为什么呢?
#进入tomcat03中查看下host配置文件
[root@VM-0-6-centos ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
#发现tomcat2直接被写在这里
172.18.0.3 tomcat02 cff25f666b32
172.18.0.4 80ed9c4e1f94
所以这里其实就是配置了一个 hosts 地址而已!
原因:--link
的时候,直接把需要 link 的主机的域名和 ip 直接配置到了 hosts 文件中了
--link
早都过时了,我们不推荐使用!我们可以使用自定义网络的方式
指令列表
[root@VM-0-6-centos ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
查看所有网络
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4b873066daf7 bridge bridge local
86da632adad6 elastic bridge local
64b606f257e7 host host local
34ab4fdb73c0 none null local
所有网路模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在 Docker 网桥 docker0 上为容器创建新的网络栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container 模式 | – net=container:name/id | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的 时候可以指定为自己定义的网络,就像 elastic |
查看一个具体的网络的详细信息
[root@VM-0-6-centos ~]# docker network inspect 4b873066daf7
[
{
"Name": "bridge",
"Id": "4b873066daf7eca3fd7a79ce17b46dff17a89368cb7f43d01c88dd9ee08d9407",
"Created": "2021-06-11T18:42:36.937993641+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
//默认 docker0 是管理这个子网范围内的。0~16,
//也就是 255*255,去掉0个255,我们有65534可以分配的ip
//所以 docker0 网络默认可以支持创建6万多个容器ip不重复
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"220fac5f16f3cf7f2619131502cb6bb4004f334c3b501a0ceff8804c361cf027": {
"Name": "tomcat01",
"EndpointID": "d54c9b71aff1843c3a1609de8eaa85785ebddd8a419ea5fae346fb538568946f",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91": {
"Name": "tomcat03",
"EndpointID": "a6dd8dd8ba2b5b341cbed8318a2463a4e28f1059cc848504a409fbf75ae21f4f",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"cff25f666b32df808923a51e14f2f2686fc9aff161e07c188c28ce15d0b38401": {
"Name": "tomcat02",
"EndpointID": "b5b18a038166b64a0308cc4a506f543b92d35b9fc50f5758f8d5daccc1df87bd",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/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": {}
}
]
1、先删除之前创建的 tomcat 镜像以及容器
2、创建容器
但是我们知道默认创建的容器都是 docker0 网卡的
#默认我们不配置网络,也就相当于默认值 --net bridge 使用的docker0
docker run -d -P --name tomcat01 --net bridge tomcat
docker0网络的特点
3、我们可以让容器创建的时候使用自定义网络
自定义创建的默认default “bridge” 一个网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4b873066daf7 bridge bridge local
64b606f257e7 host host local
7f9fbfea6931 mynet bridge local
34ab4fdb73c0 none null local
[root@VM-0-6-centos ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
"Created": "2021-06-16T15:56:58.841772626+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
我们来启动两个容器测试,使用自己的 mynet
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
来测试ping容器名和ip试试
# 都可以ping通
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.118 ms
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.059 ms
发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用 --link
效果一样,所有东西实时维护好,直接域名 ping 通。
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有 订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所 以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全部业务都在 order-net 网络下)其他业务在其他网络。
那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?
# 启动默认的容器,在docker0网络下
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat
有个命令 connect
用来连接网络
# 我们来测试一下!打通mynet-docker0
[root@VM-0-6-centos ~]# docker network connect mynet tomcat01
[root@VM-0-6-centos ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
"Created": "2021-06-16T15:56:58.841772626+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"52395d45d1fcad0170da201db471ea6ac75c25c9f7d91d10b6260dce2739fd54": {
"Name": "tomcat-net-01",
"EndpointID": "3c1aea820c4276b0d0dbe249ebd6f43547baceb7c3e774f8ee4b61b0e4b0b11f",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
//发现我们的tomcat01就进来这里了
"c159a99201d5b3f0f6be065d562c1a0e6439b316084361937f9eda9a22e997ab": {
"Name": "tomcat01",
"EndpointID": "e11948dcd704e50b8008ee41546ff7c9f506b636f41fb6e6697081fd9d398dc5",
"MacAddress": "02:42:c0:a8:00:04",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
},
"f2106d157b5ea6c5bdb87e04b9dc18be2b2e25a41d61e25851ea0afbf1e9ea39": {
"Name": "tomcat-net-02",
"EndpointID": "3cb8b199df4fca69e1a6428ae0536ff3291f9215f8b9d9303a2ec3402bdc704f",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
tomcat01 可以ping通了
[root@VM-0-6-centos ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.075 ms
tomcat02 依旧ping不通,大家应该就理解了
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER
连接
创建网卡
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个容器
for port in $(seq 1 6); \
do \
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; \
done
进入一个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
此时,六个 redis 已搭建好
测试集群
先 set 一个数据
127.0.0.1:6379> set name zhiyuan
-> Redirected to slot [5798] located at 172.38.0.12:6379
OK
172.38.0.12:6379> get name
"zhiyuan"
停止到存值的容器 redis-1
然后再次 get name
,发现依旧可以获取值
查看节点,发现高可用完全没问题
官方介绍
https://docs.docker.com/compose/
Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。借助 Compose,您可以使用 YAML 文件来配置应用程序的服务。然后,使用单个命令,从配置中创建并启动所有服务。要了解有关 Compose 的所有功能的更多信息,请参阅功能列表。
Compose 适用于所有环境:生产、登台、开发、测试以及 CI 工作流。您可以在Common Use Cases 中了解有关每个案例的更多信息。
使用 Compose 基本上是一个三步过程:
Dockerfile
以便它可以在任何地方复制。docker-compose.yml
以便它们可以在隔离的环境中一起运行。docker compose up
和 Docker compose command 启动并运行你的整个应用程序。您也可以docker-compose up
使用 docker-compose 二进制文件运行。可以用 Docker Compose 来轻松高效的管理容器。定义运行多个容器。
一个docker-compose.yml
看起来像这样:
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: {}
1、下载
官网:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
加速下载
curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
2、授权
sudo chmod +x /usr/local/bin/docker-compose
官方文档
https://docs.docker.com/compose/gettingstarted/
构建一个在 Docker Compose 上运行的简单 Python Web 应用程序。该应用程序使用 Flask 框架并在 Redis 中维护一个命中计数器。
第1 步:设置
为项目创建一个目录:
mkdir composetest
cd composetest
创建app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
在项目目录中创建 requirements.txt
flask
redis
第 2 步:创建 Dockerfile
项目目录中,创建 Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
第 3 步:在 Compose 文件中定义服务
项目目录中创建 docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
第 4 步:使用 Compose 构建并运行您的应用程序
在项目目录中运行 docker-compose up
[root@VM-0-6-centos composetest]# docker-compose up
如果要后台运行
docker-compose up -d
测试:
[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 1 times.
[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 2 times.
[root@VM-0-6-centos ~]# curl localhost:5000
Hello World! I have been seen 3 times.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jKMgOSPT-1627739909802)(https://camo.githubusercontent.com/0086f6052154a656126528da19d8a13c3b2d5b8423afd3aad0af6e6db243451e/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f6f64646661722f7374617469632f696d672f446f636b65722e6173736574732f696d6167652d32303231303631373139323234363531362e706e67)]
默认的服务名:文件名_服务名 _ num
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4b873066daf7 bridge bridge local
d87efab51b47 composetest_default bridge local
86da632adad6 elastic bridge local
64b606f257e7 host host local
34ab4fdb73c0 none null local
项目中的内容都在同个网络下。
tip 其他为演示 Compose 量身定制的示例
这些示例专门针对 Docker Compose:
官方文档
https://docs.docker.com/compose/compose-file/
# 3层!
version: '' # 版本
services: # 服务
服务1: web
# 服务配置
images
build
network
服务2: redis
....
服务3: redis
....
# 其他配置 网络/卷、全局规则
volumes:
networks:
configs:
以上实例是用 python 写的,我们写一个 java 版本的测试下
1、编写java代码
创建一个 springboot demo
@RestController
public class HelloController {
@Autowired
StringRedisTemplate redisTemplate;
@GetMapping("/hello")
public String hello(){
Long views = redisTemplate.opsForValue().increment("views");
return "hello world! views:"+ views;
}
}
2、添加配置
application.properties
文件server.port=8080
spring.redis.host=redis
Docker
文件FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
docker-compose.yml
文件version: "3.9"
services:
zhiyuanapp:
build: .
image: zhiyuanapp
depends_on:
- redis
ports:
- "8080:8080"
redis:
image: "library/redis:alpine"
3、上传并构建
把 jar包 、Docker、docker-compose 三个文件上传到一个目录下
并在此目录下构建:
[root@VM-0-6-centos zhiyuanapp]# docker-compose up
4、测试:
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:1
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:2
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:3
bridge local
d87efab51b47 composetest_default bridge local
86da632adad6 elastic bridge local
64b606f257e7 host host local
34ab4fdb73c0 none null local
项目中的内容都在同个网络下。
> tip 其他为演示 Compose 量身定制的示例
这些示例专门针对 Docker Compose:
- [快速入门:Compose 和 Django](https://docs.docker.com/samples/django/) - 展示了如何使用 Docker Compose 来设置和运行一个简单的 Django/PostgreSQL 应用程序。
- [快速入门:Compose 和 Rails](https://docs.docker.com/samples/rails/) - 展示了如何使用 Docker Compose 来设置和运行 Rails/PostgreSQL 应用程序。
- [快速入门:Compose 和 WordPress](https://docs.docker.com/samples/wordpress/) - 展示了如何使用 Docker Compose 在具有 Docker 容器的隔离环境中设置和运行 WordPress。
## yaml 规则
> 官方文档
https://docs.docker.com/compose/compose-file/
```sh
# 3层!
version: '' # 版本
services: # 服务
服务1: web
# 服务配置
images
build
network
服务2: redis
....
服务3: redis
....
# 其他配置 网络/卷、全局规则
volumes:
networks:
configs:
以上实例是用 python 写的,我们写一个 java 版本的测试下
[外链图片转存中…(img-EAwtwwmT-1627739909802)]
1、编写java代码
创建一个 springboot demo
@RestController
public class HelloController {
@Autowired
StringRedisTemplate redisTemplate;
@GetMapping("/hello")
public String hello(){
Long views = redisTemplate.opsForValue().increment("views");
return "hello world! views:"+ views;
}
}
2、添加配置
application.properties
文件server.port=8080
spring.redis.host=redis
Docker
文件FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
docker-compose.yml
文件version: "3.9"
services:
zhiyuanapp:
build: .
image: zhiyuanapp
depends_on:
- redis
ports:
- "8080:8080"
redis:
image: "library/redis:alpine"
3、上传并构建
把 jar包 、Docker、docker-compose 三个文件上传到一个目录下
并在此目录下构建:
[root@VM-0-6-centos zhiyuanapp]# docker-compose up
4、测试:
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:1
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:2
[root@VM-0-6-centos ~]# curl localhost:8080/hello
hello world! views:3