docker基于Go语言开发的!开源项目!
docker官网:https://www.docker.com/
文档:https://docs.docker.com/ Docker的文档是超级详细的!
仓库:https://hub.docker.com/
1、docker作用
1.1、分析之前的虚拟机技术
app:我们的一些应用
lib:运行所需要的库
kernel:内核
一个整体大环境放很多应用
虚拟机技术缺点:
1、 资源占用十分多
2、 冗余步骤多
3、 启动很慢!
1.2、分析容器化技术
- 容器化技术不是模拟一个完整的操作系统
-
隔离机制:每个容器相互隔离,lib和app独立,充分利用服务器资源。还有如果单个的lib崩溃了,不会导致其他的app出问题。
-
比较Docker和虚拟机技术的不同:
-
传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
-
容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
-
每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响
-
1.3、DevOps介绍
DevOps也就是指的开发和运维,有四个重要的特点:
-
应用更快速的交付和部署
- 传统:一堆帮助文档,安装程序。
- Docker:打包镜像发布测试,一键运行。(爽死)
-
更便捷的升级和扩缩容
- 使用了 Docker之后,我们部署应用就和搭积木一样。 项目打包为一个镜像,扩展服务器A!服务器B
-
更简单的系统运维
- 在容器化之后,我们的开发,测试环境都是高度一致的
-
更高效的计算资源利用
- Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致。
1.4、Docker的基本组成
好好看图,注意线条,看流程
-
镜像(image):
-
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务。
-
比如:tomcat镜像—>run命令运行—>tomcat01容器(提供服务的),通过这个镜像可以创建多个容器,如tomcat02,tomcat03等等(最终服务运行或者项目运行就是在容器中的)
-
-
容器(container):
- Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的
- 启动,停止,删除,基本命令
- 目前就可以把这个容器理解为就是一个简易的 Linux系统。
-
仓库(repository):
- 仓库就是存放镜像的地方
- 仓库分为公有仓库和私有仓库(很类似git)
- Docker Hub是国外的
- 阿里云…都有容器服务器(配置镜像加速)
2、Docker安装
环境准备
- 需要会一点点的Linux的基础
- CentOS 7及以上
- 我们使用Xshell]连接远程服务器进行操作
环境查看
[root@root /]# uname -r
3.10.0-1160.83.1.el7.x86_64
[root@root /]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
2.1、卸载旧的版本:
[root@root /]# yum remove docker \
> docker-client \
> docker-client-latest \
> docker-common \
> docker-latest \
> docker-latest-logrotate \
> docker-logrotate \
> docker-engine
Loaded plugins: fastestmirror
No Match for argument: docker
No Match for argument: docker-client
No Match for argument: docker-client-latest
No Match for argument: docker-common
No Match for argument: docker-latest
No Match for argument: docker-latest-logrotate
No Match for argument: docker-logrotate
No Match for argument: docker-engine
No Packages marked for removal
安装所需软件包:
yum install -y yum-utils
#修改阿里云镜像
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
有多个 Docker 仓库吗?
如果启用了多个 Docker 仓库,则在未在 yum install 或 yum update 命令中指定版本的情况下,进行的安装或更新将始终安装最高版本,这可能不适合您的稳定性需求。
2.2、安装Docker Engine-Community:
yum install docker-ce docker-ce-cli containerd.io
要安装特定版本的 Docker Engine-Community,请在存储库中列出可用版本,然后选择并安装:
# 列出并排序可用版本
yum list docker-ce --showduplicates | sort -r
docker-ce.x86_64 3:18.09.1-3.el7 docker-ce-stable
docker-ce.x86_64 3:18.09.0-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.1.ce-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.0.ce-3.el7 docker-ce-stable
通过其完整的软件包名称安装特定版本,该软件包名称是软件包名称(docker-ce)加上版本字符串(第二列),从第一个冒号(:)一直到第一个连字符,并用连字符(-)分隔。例如:docker-ce-18.09.1。
# 指定版本安装
yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
启动Docker:
systemctl start docker
运行hello-world:
docker run hello-world
设置国内阿里云镜像地址:
-
登录:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors ,获取专属地址
-
进入/etc/docker/,执行:
-
tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://【你的专属ID】.mirror.aliyuncs.com"] } EOF
-
重启服务:
-
systemctl daemon-reload systemctl restart docker
2.3、卸载:
# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 删除资源
rm -rf /var/lib/docker
# /var/lib/docker docker的默认资源目录
查看dockers下载的镜像
[root@root /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 19 months ago 13.3kB
2.4hello-world运行流程:
2.5、Docker底层原理
- Docker是一个Client-Server(cs)结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
- Docker-Server接收到Docker-Client的指令,就会执行这个命令!
2.6、Docker为什么比VM快:
1、 Docker有这比虚拟机更少的抽象层。
2、 Docker利用宿主机的内核,而VM需要是Guest OS。
新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统的内核,避免引导,虚拟机是加载Guest OS ,分钟级别的,而docker是利用主机的操作哦系统,省略了这个复杂的过程,秒级
3、Docker常用命令
3.1、帮助命令:
docker version # 显示docker版本信息
docker info # 显示docker系统信息,包括镜像和容器数量
docker --help # docker帮助命令
地址: https://docs.docker.com/reference/
3.2、镜像命令:
docker images 查看本机镜像
[root@root /]# docker images # 查看所有本机镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 19 months ago 13.3kB
REPOSITORY 镜像仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
# 可选项
-a # 列出所有镜像
-q # 只显示id
docker search 搜索镜像
$ docker search (name) # 搜索镜像
# 可选项
-f # 根据条件过滤 -f=STARS=3000
docker pull 拉取镜像
docker pull (name) # 拉取镜像
docker pull mysql:5.7 # 指定版本
# docker pull 镜像名[:tag] ,可选tag,不写默认latest
docker rmi 删除镜像
docker rmi -f id/name # 根据镜像id或名称删除
docker rmi -f id/name id/name id/name # 根据镜像id或名称删除多个
docker rmi -f $(docker images -aq) # 删除全部镜像
3.3、容器命令:
下载镜像
docker pull centos
镜像启动后就是容器了;通过docker ps查看容器,之后如果启动没有删除的容器,通过docker start 启动即可。
新建并启动容器
docker run [可选参数] image
# 参数说明
--name name # 容器名字
-d # 后台启动方式
-i # 使用交互方式运行,进入容器查看内容
-t # 使用交互方式运行,进入容器查看内容
-p # 指定容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-P # 随机指定端口
-v 主机目录:容器目录 # 容器卷挂载
-e # 配置环境
# 启动 并进入容器centos
docker run -it centos /bin/bash
[root@root /]# docker run -it centos /bin/bash
[root@e717714491c1 /]#
# 后台启动,给容器命名并映射端口启动
docker run -d -name name -p 主机端口:容器端口 要启动的容器名
查看运行的容器
docker ps # 列出正在运行的容器
-a # 列车曾经运行过的容器
-n=? # 最近运行过的容器
-q # 只显示容器编号
退出容器
exit #退出容器并停止
ctrl+p+q # 退出容器不停止
删除容器
docker rm 容器id # 删除指定id的容器
docker rm -f $(docker ps -aq) # 删除所有容器
docker ps -a -q|xargs docker rm # 删除所有容器
启动和停止容器
docker start 容器id # 启动容器
docker stop 容器id # 停止容器
docker restart 容器id # 重启容器
docker kill 容器id # 杀死容器
4、常用其他命令
后台启动命令
docker run -d name
# 问题doker ps 发现启动的停止了
#原因:doker容器后台运行,必须要一个前台的进程doker发现没有前台应用就会自动停止
#nginx 容器启动后发现自己没有提供服务,就会自动停止,就是没有程序了
查看日志
docker logs 参数
-t, --timestamps # 显示时间戳
-f, -follow # 跟踪日志输出
-n, --tail number # 显示日志条数
查看容器中进程信息
docker top 容器id
查看镜像源数据
docker inspect 容器id
进入当前正在运行的容器
docker exec -it 容器id /bin/bash # 打开新的终端
docker attach 容器id # 进入当前正在运行的终端
# docker exec 进入容器后开启一个新的终端,可以在里面操作(常用)
# docker attach 静茹容器正在执行的终端,不会启动新的进程
将容器内文件拷贝到主机
docker cp 容器id:容器内路径 目标主机路径
给镜像设置tag
docker tag 镜像id 信息[作者/镜像名:版本号]
小结
常用命令
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 #创建一个新的容器
diff Inspect changes to files or directories on a container's filesystem
#查看docker容器的变化
events Get real time events from the server # 从服务获取容器实时时间
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包中导入内容创建一个文件系统镜像
info Display system-wide information # 显示全系统信息
inspect Return low-level information on Docker objects #查看容器详细信息
kill Kill one or more running containers # kill指定docker容器
load Load an image from a tar archive or STDIN #从一个tar包或标准输入中加载一个镜像[对应save]
login Log in to a Docker registry #
logout Log out from a 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
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
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
wait Block until one or more containers stop, then print their exit codes
4.1、安装Nginx:
- 安装过程
#1. 搜索镜像 search 建议大家去docker搜索,可以看到帮助文档
docker search nginx
#2. 拉取下载镜像 pull
docker pull nginx
#3. 查看是否下载成功镜像
docker images
#4. 运行nginx
# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
docker run -d --name nginx01 -p 3344:80 nginx
#也就是说我们可以通过公网的3344,访问到docker的80
#5. 查看正在启动的镜像
docker ps
#6. 测试
#curl命令,利用URL规则在命令行下工作的文件传输工具
#如:curl http://www.linux.com,执行后,www.linux.com 的html就会显示在屏幕上了
#下方访问的是3344端口,显示的是nginx的网页代码,测试完毕
[root@root /]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
#7. 进入容器,查看信息
[root@root /]# docker exec -it nginx01 /bin/bash
root@1cf3f5808b4f:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@1cf3f5808b4f:/# cd /etc/nginx
root@1cf3f5808b4f:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
#注意nginx.conf,就是配置文件
-
宿主机端口 和 容器内部端口 以及端口暴露:
4.2、安装Tomcat:
# 官方的使用
docker run -it --rm tomcat:9.0
# 我们之前的启动都是后台的,停止了容器之后, 容器还是可以查到,docker run -it --rm 一般用来测试,用完就删
# 下载再启动
docker pull tomcat
# 启动运行
docker run -d -p 3344:8080 --name tomcat01 tomcat
# 测试访问没有问题
# 进入容器
docker exec -it tomcat01 /bin/bash
# 发现问题:1.linux命令少了, 2. webapps下内容为空,阿里云净吸纳过默认是最小的镜像,所有不必要的都剔除了,保证最小可运行环境即可
4.3、安装es + kibana:
# es 暴露的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录! 挂载
# --net somenetwork 网络配置
# 启动elasticsearch
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
[root@root ~]# docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
9f459fa3e96ef66009ea8bb0453edf7392a87b9b91a066c0528c3a849f0a327a
# 如果报错
docker: Error response from daemon: Conflict. The container name "/elasticsearch" is already in use by container "f08b0feb2db6b73dde47a1440c7f6b0f57b1617d99b3da9fe670ffcb3a55819f". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
#执行:docker network create somenetwork
创建一个名为somenetwork是的网卡配置
# 启动了linux就卡主了,docker stats 查看cpu状态
# 测试一下es成功了
[root@root ~]# curl localhost:9200
{
"name" : "9f459fa3e96e",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "ySZlA6CHRWW--bL21FvnwA",
"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"
}
# 增加内存限制,修改配置文件 -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.6.2
修改内存前
修改内存后
使用kibanna链接ES
可视化:
-
portainer
docker run -d -p 8080:9000 \ --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
-
Rancher(CI/CD再用)
什么是portainer?
Docker图形化界面管理工具!提供一个后台面板供我们操作!
# 安装命令
docker run -d -p 8080:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问:http://120.26.10.6:8088 访问登录界面
5、Docker镜像
5.1、镜像是什么
镜像是一种轻量级、可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。
所有应用,直接打包docker镜像,就可以直接跑起来!
如何得到镜像:
- 从远程仓库下载
- 别人拷贝给你
- 自己制作一个镜像 DockerFile
5.2、Docker镜像加载原理
UnionFs (联合文件系统)
UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
boots(boot file system)主要包含 bootloader和 Kernel, bootloader主要是引导加 kernel, Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是 boots。这一层与我们典型的Linux/Unix系统是一样的,包含boot加載器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system),在 bootfs之上。包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。 rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于个精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs.
虚拟机是分钟级别,容器是秒级!
5.4、分层理解
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过docker image inspect 命令
#查看分层命令
docker image inspect redis
[
{
"Id": "sha256:7614ae9453d1d87e740a2056257a6de7135c84037c367e1fffa92ae922784631",
"RepoTags": [
"redis:latest"
],
"RepoDigests": [
"redis@sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339"
],
"Parent": "",
"Comment": "",
"Created": "2021-12-21T12:42:49.755107412Z",
"Container": "13d25f53410417c5220c8dfe8bd49f06abdbcd69faa62a9b877de02464bb04a3",
"ContainerConfig": {
"Hostname": "13d25f534104",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"6379/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"REDIS_VERSION=6.2.6",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
"REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"redis-server\"]"
],
"Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec",
"Volumes": {
"/data": {}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"6379/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"REDIS_VERSION=6.2.6",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
"REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
],
"Cmd": [
"redis-server"
],
"Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec",
"Volumes": {
"/data": {}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 112691373,
"VirtualSize": 112691373,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ca334263a60756d34c0025092199d4a9723638c3094e8f109c23eb917d3b23de/diff:/var/lib/docker/overlay2/33f6ed74e0c6ee39b6f2865bba496964685fcf1fd77bfb4d3030de57dec8d212/diff:/var/lib/docker/overlay2/bc941d5f01f0c50d8810db8995c5c76d1b208d028670cedbb56114a126155bc9/diff:/var/lib/docker/overlay2/b444556b32389ddf8d3170319384ef4b434d94ee5df66a5f6cddda5c561db239/diff:/var/lib/docker/overlay2/383ab0cf81eaf8a20d811a3fb7a87fce42caed85ceee5fe245372c5e4f696bc8/diff",
"MergedDir": "/var/lib/docker/overlay2/0a3787bc78f7465860ee85120324dedafeb385bc6e73ba441bca9faca15eed3c/merged",
"UpperDir": "/var/lib/docker/overlay2/0a3787bc78f7465860ee85120324dedafeb385bc6e73ba441bca9faca15eed3c/diff",
"WorkDir": "/var/lib/docker/overlay2/0a3787bc78f7465860ee85120324dedafeb385bc6e73ba441bca9faca15eed3c/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
"sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb",
"sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1",
"sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372",
"sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed",
"sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
理解:
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,
就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。
文种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统
Linux上可用的存储引撃有AUFS、 Overlay2、 Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于 Linux中对应的
件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。
Docker在 Windows上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW [1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。
特点
Docker 镜像都是只读的,当容器启动时, 一个新的可写层加载到镜像的顶部!
这一层就是我们通常说的容器层, 容器之下的都叫做镜像层
5.5、commit镜像(提交自己的镜像)
打包自己的镜像,类似于Linux快照操作。
docker commit #提交容器成为一个新的镜像
docker commit -m="信息" -a="作者" 容器id 目标镜像名:[TAG版本号]
测试:
#1. 启动一个默认的tomcat
[root@root ~]# docker run -it -p 8080:8080 tomcat
#2. 发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的!
[root@root ~]# docker exec -it 6a247eda1614 /bin/bash
#3. 将webapps.dist里的所有东西拷贝文件进webapps,并查看
root@6a247eda1614:/usr/local/tomcat# cd webapps
root@6a247eda1614:/usr/local/tomcat/webapps# ls
root@6a247eda1614:/usr/local/tomcat/webapps# cd ..
root@6a247eda1614:/usr/local/tomcat# ls
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@6a247eda1614:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@6a247eda1614:/usr/local/tomcat# cd webapps
root@6a247eda1614:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@6a247eda1614:/usr/local/tomcat/webapps# exit
exit
#4. 操作过的容器通过commit调教为一个镜像!我们以后就使用我们修改过的镜像即可,而不需要每次都重新拷贝webapps.dist下的文件到webapps了,这就是我们自己的一个修改的镜像。
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="hwt" -m="add webapps app" 6a247eda1614 tomcat02:1.0
[root@root ~]# docker commit -a="hwt" -m="add webapps app" 6a247eda1614 tomcat02:1.0
[root@root ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
#看下方这个tomcat02.1.0就是我们创建的镜像,发布之后再说
tomcat02 1.0 bf96397625ab 8 seconds ago 684MB
nginx latest 605c77e624dd 15 months ago 141MB
tomcat 9.0 b8e65a4d736d 16 months ago 680MB
tomcat latest fb5657adc892 16 months ago 680MB
redis latest 7614ae9453d1 16 months ago 113MB
mysql 5.7 c20987f18b13 16 months ago 448MB
hello-world latest feb5d9fea6a5 19 months ago 13.3kB
centos latest 5d0da3dc9764 19 months ago 231MB
portainer/portainer latest 580c0e4e98b0 2 years ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 3 years ago 791MB
6、容器数据卷
6.1、什么是容器数据卷
docker的理念是将应用和环境打包成一个镜像!
如果数据都在容器中,那么我们容器删除,数据就会丢失!所以我们就有需求:数据可以持久化
比如:安装了MySQL,容器删除了,相当于删库跑路!所以我们就有需求:MySQL数据可以存储在本地!
所以我们需要容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!说白了就是目录的挂载,将我们容器内的目录,挂载到Linux上面!
总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
6.2、使用数据卷
方式一 :直接使用命令挂载 -v
docker run -it -v 主机目录:容器目录
[root@root home]# docker run -it -v /home/ceshi:/home centos /bin/bash
# 启动起来之后可以通过docker inspect 容器id
测试文件的同步:
继续测试
- 停止容器
- 宿主机上修改文件
- 启动容器
- 容器的数据依旧是同步的
好处:我们以后修改只需要在本地修改即可,容器内会自动同步!
实战:安装MySQL
#1. 获取mysql镜像
[root@root home]# docker pull mysql:5.7
#2. 运行容器的时候需要做数据挂载,此处我们挂载了配置文件以及数据目录(有两个哦),同时咱们也配置了mysql的密码
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
-- name 容器名字
[root@iZ2vc28obhvfham8wewhh0Z ~]# 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=root --name mysql 01 mysql:5.7
#3. 启动成功之后,我们可以在本地使用sqlyog来接入测试
# 测试连接到服务器的3310 --- 3310 和容器内的 3306 映射这个时候就链接到了
#在本地创建一个数据库 查看映射路径发现容器内也增加同步过来了
就算是将容器删除,挂载到本地的数据卷依旧没有缺失,这就实现了数据持久化功能
6.3、具名和匿名挂载
匿名挂载
当
-v
没有指定本地目录时,而是只指定了容器内目录,则匿名挂载。他会生成一个随机字符串名称作为本地目录名;
# 匿名挂载
[root@root ~]# docker run -d -P --name nginx01 -v /etc/nginx nginx
808f57f0b2761e7dbedc55b7b5f4f2a0a3c6d8f787af28c43eee6cbe397c624f
# 启动之后查看挂载信息,可以看到生成了一个很长的名字
[root@root ~]# docker volume ls
DRIVER VOLUME NAME
local 4a9000076681c93f5c1c68a22184224cba3a5bff78c72a444700d16e85929432
local 59a7bcb1858a64e6f70c1a360e2dd34ac848a4ce2654c9b7ce70832d8030d546
local 5164a418a0559bfe8144dc91783b9b0fe9279285379995a073e963aa0b1f2d85
local a60aefe0bb6c0faf7e95c1a34e98da64faf1aca46c97ff3add7357060fa543b4
# 根据生成的名字查看具体挂载到本地位置目录
[root@root ~]# docker inspect 808f57f0b2761e7dbedc55b7b5f4f2a0a3c6d8f787af28c43eee6cbe397c624f
[
{
"CreatedAt": "2021-03-19T22:50:49+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/65b1f54c7f22614ed5920b623e208bfefc0a6b0bef2b721559bb2e2ce284b851/_data",
"Name": "65b1f54c7f22614ed5920b623e208bfefc0a6b0bef2b721559bb2e2ce284b851",
"Options": null,
"Scope": "local"
}
]
# "Mountpoint" 值就是挂载本地目录。
具名挂载
挂载时指定名称
# 指定名称为 juming-guazai
[root@root ~]# docker run -d -P --name nginx02 -v juming-guazai:/etc/nginx nginx
5e04b9325aaf2a3c39ff24a3335f2b3d5e617797e057f445bdae37dc867d308f
# 查看挂载
[root@root ~]# docker volume ls
DRIVER VOLUME NAME
local 4a9000076681c93f5c1c68a22184224cba3a5bff78c72a444700d16e85929432
local 59a7bcb1858a64e6f70c1a360e2dd34ac848a4ce2654c9b7ce70832d8030d546
local 5164a418a0559bfe8144dc91783b9b0fe9279285379995a073e963aa0b1f2d85
local a60aefe0bb6c0faf7e95c1a34e98da64faf1aca46c97ff3add7357060fa543b4
local juming-guazai
# 通过挂载名查看本地具体位置目录
[root@root ~]# docker inspect juming-guazai
[
{
"CreatedAt": "2023-04-22T09:47:24+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-guazai/_data",
"Name": "juming-guazai",
"Options": null,
"Scope": "local"
}
]
所有的docker容器内的卷,没有指定目录的情况下挂载位置在:/var/lib/docker/volumes/挂载名/_data
扩展: 通过在 -v 容器内路径:ro/rw
改变容器内路径读写权限!
ro readonly #只读
rw readwrite #可读写
docker run -d -P --name nginx02 -v juming-guazai:/etc/nginx:ro nginx
6.4、数据卷容器
容器之间数据共享
--volumes-from 父容器
7、Dockerfile
7.1、什么是Dockerfile
Dockerfile 是一个用来构建镜像的文本文件
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!
步骤:
- 编写一个dockerfile文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像
# 创建一个dockerfile文件, 名字可以随机
# 文件的内容 指定(大写) 参数
FROM centos
VOLUME ["volume01", "volume02"]
CMD echo "----end----"
CMD /bin/bash
# 这里的每一个命令都是镜像的一层!
启动自己创建的容器
# docker inspect 容器id 查看 Docker 容器的详细信息,包括容器的镜像、名称、状态、容器运行时环境等信息。
[root@root /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4ffeab47d952 30867ff50a2c "/bin/bash" 15 minutes ago Up 15 minutes eloquent_blackwell
5e04b9325aaf nginx "/docker-entrypoint.…" 38 minutes ago Up 38 minutes 0.0.0.0:32769->80/tcp, :::32769->80/tcp nginx02
808f57f0b276 nginx "/docker-entrypoint.…" 55 minutes ago Up 55 minutes 0.0.0.0:32768->80/tcp, :::32768->80/tcp nginx01
[root@root /]# docker inspect 4ffeab47d952
通过测试发现数据同步到了主机上
这种方式我们未来使用的十分多, 因为我们通常会构建自己的镜像!
假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!
7.1、数据卷容器
多个mysql同步数据!
[root@root home]# docker run -it --name docker01 hwt/centos:1.0
[root@dcddb933ac72 /]# ls -l
total 56
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 360 Apr 22 02:59 dev
drwxr-xr-x 1 root root 4096 Apr 22 02:59 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
.....
drwxr-xr-x 2 root root 4096 Apr 22 02:59 volume01
drwxr-xr-x 2 root root 4096 Apr 22 02:59 volume02
[root@root home]# docker run -it --name docker02 --volumes-from docker01 hwt/centos:1.0
[root@f9f72b54d0ab /]# ls -l
total 56
....
[root@f9f72b54d0ab volume01]# ls
docker01
测试删除docker01 查看docker02和docker03是否还可以访问这个文件
结果依旧可以访问到
多个mysql实现数据共享
docker run -d -p 3344:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql01 mysql:5.7
docker run -d -p 3344:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql02 --volumes-from mysql01 mysql:5.7
# 这个时候就可以实现连哥哥容器的数据共享
7.3、Dockerfile构建过程
认识:
- 每个关键字命令都必须大写;
- 命令是从上到下执行的;
#
表示注释;- 每一个指令都会创建提交一个新的镜像层;
dockerFile是面向开发的, 我们以后要发布项目, 做镜像, 就需要编写dockefile文件, 这个文件十分简单!
Docker镜像逐渐成为企业的交互标准,必须要掌握!
步骤:开发,部署, 运维… 缺一不可!
DockerFile: 构建文件, 定义了一切的步骤,源代码
DockerImages: 通过DockerFile构建生成的镜像, 最终发布和运行的产品!
Docker容器:容器就是镜像运行起来提供服务器
Dockerfile 是面向开发的,项目的发布就需要做镜像,就需要编写dockerfile文件;
Dockerfile指令:
FROM # 基础镜像,镜像从这里开始
MAINTAINER # 镜像是谁写的
RUN # docker镜像构建的时候运行的命令
ADD # 给镜像添加内容,添加组件,如果是tar包可以自动解压
WORKDIR # 镜像的工作目录
VOLUME # 挂载卷目录
EXPOSE # 暴露端口配置
CMD # 指定容器启动的时候运行的命令,不可以追加命令 会被替换
ENTRYPOINT # 指定容器启动的时候运行的命令,可以追加命令,不会替换
ONBUILD # 当构建一个被继承的dockerfile时就会触发
COPY # 将文件拷贝到目录中
ENV # 构建的时候设置环境变量
LABEL # 设置镜像的标签
7.4练习创建自定义镜像
指令
# 编写构建镜像文件
[root@root dockerfile]# vim mydockerfile-centos
[root@root dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER hwt<2813068665@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
[root@root dockerfile]# docker build -f mydockerfile-centos -t mycentos:1.0 .
# 构建镜像
docker build -f 镜像文件 -t 镜像名 .
列出本地镜像变更历史 ,构建信息
docker history 镜像id
CMD 和ENTRYPOINT区别:
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令, 可以追加命令
7.5、自定义tomcat环境镜像centos
-
准备镜像文件 tomcat压缩包,jdk的压缩包!
-
编写Dockerfile文件,官方命名
Dockerfile
, build会自动寻找这个文件,就不需要-f指定了!#1. 创建Dockerfile文件,官方建议名称为Dockerfile #Dockerfile的内容如下: #----------------------------------- # 基础镜像centos FROM centos:7 # 作者信息编写 MAINTAINER hwt<2813068665@qq.com> # 添加jdk,ADD 命令会自动解压到/usr/local目录 ADD jdk-8u361-linux-x64.rpm /usr/local/ # 添加tomcat,ADD 命令会自动解压到/usr/local目录 ADD apache-tomcat-9.0.73.tar.gz /usr/local/ # 安装 vim 命令 RUN yum -y install vim # 设置MYPATH ENV MYPATH /usr/local # 工作目录,引用MYPATH WORKDIR $MYPATH # 配置环境变量:JAVA_HOME环境变量 ENV JAVA_HOME /usr/local/jdk1.8.0_361 # 配置CLASSPATH ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar # 环境变量: tomcat环境变量 ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.73 ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.73 # 设置环境变量 分隔符是: ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin # 设置暴露的端口 EXPOSE 8080 # 设置默认命令,这里设置了启动指定目录下的startup.sh程序以及日志 CMD /usr/local/apache-tomcat-9.0.73/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.73/bin/logs/catalina.out #2. 创建一个readme.txt的文件 touch readme.txt
-
构建镜像;如果构建文件名为Dockerfile,则构建镜像时不需要写构建文件位置
[root@node1 tomcat]# docker build -t mytomcat .
-
构建镜像成功!
查看本地镜像是否有构建成功的镜像
-
运行镜像,同时挂载项目目录和日志目录;
[root@root tomcat]# docker run -d -p 9090:8080 --name mytomcat -v /home/hwt2/build/tomcat/test:/usr/local/apache-tomcat-9.0.73/webapps/test -v /home/hwt2/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-9.0.73/logs divtomcat
此时可以在挂载目录test项目下放入相关web页面;
在本地编写web.xml和index.jsp进行测试
WEB-INF下新建web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
6666<br/>
<%
System.out.println("-----666666------");
%>
</body>
</html>
7.6、发布镜像
发布到Docker Hub
- 注册账号:https://hub.docker.com/
- 登录
[root@root tomcat]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a registry.
If no server is specified, the default is defined by the daemon.
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
[root@root tomcat]# docker login -u hwt6
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
提交镜像docker push
#修改镜像名 镜像id 新名字
docker tag 169ea7da7330 hwt6/tomcat:1.0
#docker push 文件名/镜像名:版本号
[root@root tomcat]# docker push hwt6/tomcat:1.0
提交的时候也是按照层级提交的
发布到阿里云镜像
- 登录阿里云
- 打开容器镜像服务
- 创建命名空间
- 创建容器镜像
- 推送
7.7、总结
现在看这个图,问题不大。图中的save和load是本地的镜像压缩备份,我们一般选择push直接上传到dockerhub或者阿里云
8、Docker网络
清空所有镜像
# 列出当前运行中的镜像
docker ps
#停止运行该id的镜像
docker stop e39146c13894
#删除所有镜像
docker rmi -f $(docker images -aq)
查看本地镜像
docker images
8.1、Docker网络ip
查看本地网络信息
可见有三个网卡信息,lo:本地 ;ens:虚拟机或阿里云服务器地址;docker0:docker网络地址。
下面报错没有命令的 容器内执行解决方式:
从软件源获取最新的软件包列表并且下载安装 iproute2 软件包及其依赖项。 apt update && apt install -y iproute2
查看docker容器启动时的内部网络;分别启动两个容器;
docker run -d -P --name tomcat04 tomcat
#查看容器的内部网络地址 ip addr , 发现容器启动的时候会得到一个 eth0@if11 ip地址 docker分配的
[root@root ~]# docker exec -it tomcat04 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> 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
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
#测试linux能不能ping通容器
[root@root ~]# ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.072 ms
64 bytes from 172.17.0.4: icmp_seq=4 ttl=64 time=0.047 ms
64 bytes from 172.17.0.4: icmp_seq=5 ttl=64 time=0.072 ms
64 bytes from 172.17.0.4: icmp_seq=6 ttl=64 time=0.045 ms
^C
--- 172.17.0.4 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 4999ms
rtt min/avg/max/mdev = 0.045/0.058/0.072/0.014 ms
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0(桥接模式),使用的技术是veth-pair技术!
-
我们测试ip addr,发现多了一个10和11
-
我们再启动一个tomcat05,发现又多了一个24和25
-
小结:
我们发现这个容器带来网卡,都是一对对的 veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连 正因为有这个特性 veth-pair 充当一个桥梁,连接各种虚拟网络设备的 OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
-
我们再来尝试一下容器之间能否ping通,结论:可以ping通!直接画图理解:
如果容器内没有安装ping命令则执行: apt-get install inetutils-ping 安装ping命令
结论:tomcat01和tomcat02是共用的一个路由器,docker0
所有容器不指定网络的情况下,都是docker0路由的,doucker会给我们的容器分配一个默认的可用IP
小结
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0
Docker中的所有的网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件!)
只要容器删除,对应的网桥一对就没有了!
8.2、–link
需求,每次重启容器或Linux,ip就会变化,固定的ip互联网络就会失效,如何使用服务名来连接,而不考虑ip?
测试使用容器名来ping
[root@root ~]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known
[root@root ~]#
容器之间无法通过容器名来连接;
如何解决?
[root@root ~]# docker run -d -P --name tomcat09 --link tomcat07 tomcat
8a834bd9c3c401ecfc454ceb322e3f9cc8ffccdcc04662d69f6483ea80e4a28b
[root@root ~]# docker exec -it tomcat09 ping tomcat07
PING tomcat07 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.174 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.130 ms
^C--- tomcat07 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.130/0.152/0.174/0.000 ms
# 但是反向却无法链接通!!!
tomcat09能够通过容器名链接tomcat07,原理是–link 是通过tomcat09在自己容器hosts文件中配置了tomcat07 ip信息!
[root@root ~]# docker exec -it tomcat09 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
172.17.0.3 tomcat07 59106d96228b
172.17.0.5 8a834bd9c3c4
本质就是修改host映射,–link已经摒弃;建议实现使用自定义网络实现!
8.3、自定义网络
查看本地docker网络信息
[root@root ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ba12df0f9aa6 bridge bridge local
e379cdacfac2 es bridge local
0d4f6c0df3b3 host host local
5b531cef8601 none null local
e52ae9b4207b somenetwork bridge local
- bridge : 桥接(默认,自己创建也使用bridge)
- host : 和宿主即共享
- none : 不配置网络
# 删除所有容器
[root@root ~]# docker rm -f $(docker ps -aq)
# 我们直接启动的命令 --net bridge 这个就相当于docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --net bridge --name tomcat01 tomcat
# docker0 特点,默认的,域名不能访问 --link可以打通连接
# 所以我们可以指定自定义的网络
# 通过docker network --help
[root@root ~]# 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.
创建自定义的网络
docker create
[root@root ~]# docker network create -d bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
9b2c349093073aa9527b4ef8f7cc3344ad224b9b9eb2c3f522c7fcb6fd0322b3
-d --driver 网络模式
--subnet 子网
--gateway 网关
---------------------------------------------
# 命令参数详解
[root@root ~]# docker network create --help
Usage: docker network create [OPTIONS] NETWORK
Create a network
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which to copy the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
查看我们创建的网络
[root@root ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ba12df0f9aa6 bridge bridge local
e379cdacfac2 es bridge local
0d4f6c0df3b3 host host local
9b2c34909307 mynet bridge local
5b531cef8601 none null local
e52ae9b4207b somenetwork bridge local
查看自定义网络
自定义网络创建完成!
之后容器启动可以将网络配置在自定义网络下,解决了–link的不足!
# 启动两个容器
[root@root ~]# docker run -d -P --net mynet --name tomcat01-net-01 tomcat
[root@root ~]# docker run -d -P --net mynet --name tomcat01-net-02 tomcat
# 不同容器同处于同一网络下mynet,维护好了容器间的关系。
root@24420c5c2183:/usr/local/tomcat# read escape sequence
[root@root ~]# docker exec -it tomcat01-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.154 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.138 ms
^C^C--- 192.168.0.3 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.111/0.130/0.154/0.000 ms
查看mynet网络信息
[root@node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
8d5e54eaae69 bridge bridge local
3452d41b8d68 host host local
30d7111860cf mynet bridge local
c98ef8bfc64b none null local
[root@node1 ~]# docker network inspect 30d7111860cf
可以实现不同集群使用不同的网络,保证集群网络的安全和健康;
如Redis集群在192.160.0.0/16网段下,mysql集群在192.161.0.0/16网段下。
8.4、网络连通
场景:
测试打通tomcat01 和mynet
解决: 使用
docker network connect
实现。
#语法:docker network connect [OPTIONS] NETWORK CONTAINER
#1. 之前删除的tomcat01和tomcat02创建好
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat
#2. 打通tomcat01和mynet
docker network connect mynet tomcat01
#3. 查看网络配置,如下图所示:
docker network inspect mynet
# 要将tomcat01 连通 tomcat—net-01 ,连通就是将 tomcat01加到 mynet网络
# 一个容器两个ip(tomcat01)
测试连通:
[root@root ~]# docker exec -it tomcat01-net-01 ping tomcat01
PING tomcat01 (192.168.0.4): 56 data bytes
64 bytes from 192.168.0.4: icmp_seq=0 ttl=64 time=0.156 ms
64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.120 ms
64 bytes from 192.168.0.4: icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from 192.168.0.4: icmp_seq=3 ttl=64 time=0.114 ms
^C--- tomcat01 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.114/0.127/0.156/0.000 ms
9、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
# 创建结点1
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
#创建结点2
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
#创建结点3
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
#创建结点4
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
#创建结点5
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
#创建结点6
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
# 创建集群
[root@root conf]# docker exec -it redis-1 /bin/sh
/data # ls
appendonly.aof nodes.conf
/data # 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:637
79 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 53eab5178492fd576f5f3d86b1c6a5400dd5b820 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 9ac04371d9db47317ea7f50012b350d55c4ef5e3 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: e749dd5cbf37951ec8822352d92961fc01411e90 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: dbbef8c10be71c8e45d360fdd035d16ddf65f204 172.38.0.14:6379
replicates e749dd5cbf37951ec8822352d92961fc01411e90
S: e8b9337658171043ed9ef6b351a71f397b69b3bc 172.38.0.15:6379
replicates 53eab5178492fd576f5f3d86b1c6a5400dd5b820
S: a988d3ac588e4ff564092470771b9541d253cc51 172.38.0.16:6379
replicates 9ac04371d9db47317ea7f50012b350d55c4ef5e3
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 53eab5178492fd576f5f3d86b1c6a5400dd5b820 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: a988d3ac588e4ff564092470771b9541d253cc51 172.38.0.16:6379
slots: (0 slots) slave
replicates 9ac04371d9db47317ea7f50012b350d55c4ef5e3
M: e749dd5cbf37951ec8822352d92961fc01411e90 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: dbbef8c10be71c8e45d360fdd035d16ddf65f204 172.38.0.14:6379
slots: (0 slots) slave
replicates e749dd5cbf37951ec8822352d92961fc01411e90
S: e8b9337658171043ed9ef6b351a71f397b69b3bc 172.38.0.15:6379
slots: (0 slots) slave
replicates 53eab5178492fd576f5f3d86b1c6a5400dd5b820
M: 9ac04371d9db47317ea7f50012b350d55c4ef5e3 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
--------------------测试-------------------------------
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
172.38.0.13:6379> get a
Could not connect to Redis at 172.38.0.13:6379: Host is unreachable
(33.82s)
not connected>
/data # redis-cli -c
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
测试存入数据之后删除主镜象:
[root@root ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d8dce4527ba6 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 0.0.0.0:6376->6379/tcp, :::6376->6379/tcp, 0.0.0.0:16376->16379/tcp, :::16376->16379/tcp redis-6
fc84445e7601 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 0.0.0.0:6375->6379/tcp, :::6375->6379/tcp, 0.0.0.0:16375->16379/tcp, :::16375->16379/tcp redis-5
5d151352d7cd redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 0.0.0.0:6374->6379/tcp, :::6374->6379/tcp, 0.0.0.0:16374->16379/tcp, :::16374->16379/tcp redis-4
b69bbff6e0e6 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 0.0.0.0:6373->6379/tcp, :::6373->6379/tcp, 0.0.0.0:16373->16379/tcp, :::16373->16379/tcp redis-3
add6c2b74c1c redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 0.0.0.0:6372->6379/tcp, :::6372->6379/tcp, 0.0.0.0:16372->16379/tcp, :::16372->16379/tcp redis-2
e73a43d175f3 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 0.0.0.0:6371->6379/tcp, :::6371->6379/tcp, 0.0.0.0:16371->16379/tcp, :::16371->16379/tcp redis-1
[root@root ~]# docker stop redis-3
redis-3
[root@root ~]#
使用docker之后会变得更加简单
10、SpringBoot微服务打包Docker镜像
-
构建springboot项目
-
打包应用
-
编写Dockerfile
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app.jar"]
-
-
构建镜像
-
发布运行!
# 把jar包构建为镜像 docker build -t hwt666 . # 运行docker镜像 docker run -d -P --name hwt-springboot-web hwt666 # 测试访问 [root@root idea]# curl localhost:32781/hello hello docker[root@root idea]#
四台机器安装docker
和我们单机安装一样
技巧: xshell直接同步操作,省时间!
Swarm集群搭建
Docker Engine 1.12 introduces swarm mode that enables you to create a cluster of one or more Docker Engines called a swarm. A swarm consists of one or more nodes: physical or virtual machines running Docker Engine 1.12 or later in swarm mode.
There are two types of nodes: managers and workers.
docker swarm init --help
ip addr # 获取自己的ip(用内网的不要流量)
[root@localhost ~]# docker swarm init --advertise-addr 192.168.29.130
Swarm initialized: current node (lx0lbv9i1cui04kqeiej1pbjb) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0tp5ijg39u8gn8jnceymrfe6lc8g9ca2w2thbk1922vhkh4mp8-7kr1qko1dgrz75g34axvn9f6i 192.168.29.130:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
初始化结点docker swarm init
docker swarm join 加入一个结点!
# 获取令牌
docker swarm join-token manager
docker swarm join-token worker
[root@localhost ~]# docker swarm join --token SWMTKN-1-0tp5ijg39u8gn8jnceymrfe6lc8g9ca2w2thbk1922vhkh4mp8-7kr1qko1dgrz75g34axvn9f6i 192.168.29.130:2377
This node joined a swarm as a worker.
把后面的结点都搭建进去
两种可能出现的报错以及解决方式:
-
主节点防火墙未关闭
#报错信息 Error response from daemon: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial tcp 192.168.0.108:2377: connect: no route to host" # 查看当前防火墙状态 [root@localhost ~]# systemctl status firewalld.service # 关闭防火墙 [root@localhost ~]# systemctl stop firewalld.service # 永久停止防火墙 [root@localhost ~]# systemctl disable firewalld.service
-
端口未打开
# 报错信息 [root@localhost ~]# docker swarm join --token SWMTKN-1-0tp5ijg39u8gn8jnceymrfe6lc8g9ca2w2thbk1922vhkh4mp8-7fh11rblokyz15sa7f26hwimy 192.168.29.130:2377 Error response from daemon: manager stopped: can't initialize raft node: rpc error: code = Unknown desc = could not connect to prospective new cluster member using its advertised address: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 192.168.29.133:2377: connect: no route to host" # 在docker4上查看2377端口开放情况,发现没有任何端口 [root@localhost ~]# firewall-cmd --zone=public --list-ports # 在docker4上开放2377端口 [root@localhost ~]# firewall-cmd --zone=public --add-port=2377/tcp --permanent success [root@localhost ~]# firewall-cmd --reload success
100台!
- 生成主节点init
- 加入(管理者,worker)