docker学习

文章目录

基本结构

镜像(image):

docker镜像可以当作一个模板,通过这个模板可以创建多个容器。

例如一个tomcat镜像=>运行=>容器(提供服务)

容器(container):

docker利用容器技术,可以独立运行一个或一组应用(容器间相互隔离)

docker容器通过镜像来创建,即容器中的进程依赖于镜像中的文件。

docker容器类似于虚拟机,可以启动,停止,删除等。可以把docker当作一个简易的Linux系统。

仓库(repository):

存放镜像的地方。分为公有仓库和私有仓库。

默认是使用国外的仓库docker hub。

流程及原理

流程:

以第一层docker run hello-world为例

在本机寻找镜像-->判断是否有该镜像

如果有该镜像-->直接运行

如果没有这个镜像-->去所设置的源中寻找这个镜像-->下载-->运行

原理:

docker是一个CS结构系统,docker的守护进程在主机上。通过socket从客户端访问,docker-server接收到docker-client指令,就好执行该命令。

常用命令

帮助命令
shell 复制代码
docker version  #查看docker版本信息
docker info    #显示docker系统信息,比version更相信
docker 命令 --help   #docker --help直接查看帮助信息

docker官方文档:https://docs.docker.com/engine/reference/commandline

镜像命令

docker images 查看所有本地主机上的镜像

shell 复制代码
root@VM-4-17-ubuntu:/home/ubuntu# docker images
REPOSITORY    TAG                        IMAGE ID       CREATED         SIZE
tophant/arl   v2.6.1                     658157563173   10 months ago   1.19GB
hello-world   latest                     d2c94e258dcb   18 months ago   13.3kB

#解释
REPOSITORY  镜像的仓库源
TAG         镜像标签
IMAGE ID    镜像id
CREATED     镜像创建时间
SIZE        镜像大小

#可选项
docker images --help #查看可选项
-a, -all  #列出所有镜像
-q, -quiet #只显示镜像id
-f, --filter filter(过滤器)   filter可以是dangling=true(悬空镜像)
    --format string(格式化字符串)   string可以是json table等
也可以直接docker images 后面跟上镜像的名称 搜索指定镜像

docker search 搜索镜像(如果配置的是国内的镜像源会超时)

shell 复制代码
docker search images(写镜像名称即可)

docker pull 下载镜像

shell 复制代码
docker pull 镜像名称(默认是最新版本)
docker pull 镜像名称[:tag]  #指定版本

root@VM-4-17-ubuntu:/home/ubuntu# docker pull mysql
Using default tag: latest   #如果不写,默认就是latest
latest: Pulling from library/mysql
f1a9f94fc2db: Pull complete   #分层下载
f98254a2b688: Pull complete 
6ad83e89f981: Pull complete 
a42d733ea779: Pull complete 
6fd1af2601dd: Pull complete 
0233a63dc5cd: Pull complete 
5f31e56c9bea: Pull complete 
c0fb96d14e5b: Pull complete 
d57074c62694: Pull complete 
7030c241d9b8: Pull complete 
Digest: sha256:2be51594eba5983f47e67ff5cb87d666a223e309c6c64450f30b5c59a788ea40 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest   #真实地址

docker pull mysql 等价于 docker pull  docker.io/library/mysql:latest
docker pull mysql:5.7 #下载指定5.7版本的mysql

docker rmi -f 删除镜像

shell 复制代码
docker rmi -f 镜像名称或ID  
docker rmi -f $(docker images)  #批量删除所有镜像

docker commit 提交镜像

shell 复制代码
docker commit 提交容器成为一个新副本
#与git类似
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名[:tag]
容器命令

有镜像才能创建容器,下载一个centos镜像来测试

shell 复制代码
docker pull centos  #下载centos镜像

新建容器,并启动

shell 复制代码
docker run [可选项] image 使用的shell

#参数
--name='Name'  #容器名字
-d			   #后台方式运行
-it			   #使用交互方式运行,进入容器查看内容
-p			   #指定容器端口
	-p 主机端口:容器端口 (常用)
	-p ip:主机端口:容器端口
	-p 容器端口
-P 			   #随机指定端口
-e             #环境配置
#启动并且进入容器,以/bin/bash启动交互
root@VM-4-17-ubuntu:/home/ubuntu# docker run -it centos /bin/bash
#此时已经进入centos
[root@edcaca222a0c /]# 
[root@edcaca222a0c /]# exit 
退出容器

docker ps 查看正则运行的容器

shell 复制代码
docker ps

#可选项
-a    #查看历史运行过的容器
-n=? #显示最近创建的容器
-q    #只显示编号

exit 退出容器

shell 复制代码
exit  #直接停止容器并退出
Ctrl+P+Q #容器不停止,但退出

docker rm 删除容器

shell 复制代码
docker rm 容器id  #删除所有容器(正在运行的容器不能删除)
docker rm -d 容器id #强制删除
docker rm -f $(docker ps -sq)  #删除全部容器

启动和停止容器

shell 复制代码
docker start 容器id   #启动容器
docker restart 容器id #重启容器
docker stop 容器id    #停止容器
docker kill 容器id    #强制停止容器
其他命令

后台启动容器

shell 复制代码
docker run -d centos #后台运行centos
但是会停止,因为容器使用后台时,需要有一个前台进程,docker发现没有应用,就会自动停止

查看日志

shell 复制代码
docker logs 

#可选项
--details    #详细显示    
-f    
	--follow         
    --since string   
-n
	--tail number #要显示的日志的条数   
-t    #显示时间戳
	--timestamps      
    --until
    
例:
docker logs -f -t --tail 10 bdc75926ba54  #查看容器id为bdc75926ba54的近十条日志
#自己写一段脚本
docker run -d centos /bin/bash -c "while true;do echo success;sleep 1;done"
docker ps

查看容器中的进程信息

shell 复制代码
docker top 容器ID   

查看进程源数据

shell 复制代码
docker inspect 容器ID   #很详细的信息
root@VM-4-17-ubuntu:/home/ubuntu# docker inspect bdc75926ba54
[
    {
        "Id": "bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07",
        "Created": "2024-11-18T12:42:53.59866176Z",
        "Path": "/bin/bash",
        "Args": [
            "-c",
            "while true;do echo success;sleep 1;done"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3288327,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2024-11-18T12:42:53.709853768Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "ResolvConfPath": "/var/lib/docker/containers/bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07/hostname",
        "HostsPath": "/var/lib/docker/containers/bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07/hosts",
        "LogPath": "/var/lib/docker/containers/bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07/bdc75926ba5407e16b35c9bc7f3ae0458f42760de6cd4438b5241107ca45cd07-json.log",
        "Name": "/nervous_hamilton",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "docker-default",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "bridge",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                23,
                168
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": [],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware",
                "/sys/devices/virtual/powercap"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/e1f14591fd92ea633340505f56178f100b15e4b3c3d5c99d4cd6fdce7b45f0fb-init/diff:/var/lib/docker/overlay2/d3b747475083e2e4f9f55fdbd0bfcb7014302c609b6e78e71285b3cbc167ada9/diff",
                "MergedDir": "/var/lib/docker/overlay2/e1f14591fd92ea633340505f56178f100b15e4b3c3d5c99d4cd6fdce7b45f0fb/merged",
                "UpperDir": "/var/lib/docker/overlay2/e1f14591fd92ea633340505f56178f100b15e4b3c3d5c99d4cd6fdce7b45f0fb/diff",
                "WorkDir": "/var/lib/docker/overlay2/e1f14591fd92ea633340505f56178f100b15e4b3c3d5c99d4cd6fdce7b45f0fb/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "bdc75926ba54",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash",
                "-c",
                "while true;do echo success;sleep 1;done"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f917fe5b9d9b12a387c0839145d48519157f1cc1de48ff5946de78dadb34e7f2",
            "SandboxKey": "/var/run/docker/netns/f917fe5b9d9b",
            "Ports": {},
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "4c25273ed065481b657a6b4878f81d5edcd6d82054d34a5fb197908f75765a3c",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null,
                    "NetworkID": "1d4a3714574bf3de87a9553dfc005fad8166af95134e91e3b2bb80c9ac3a65b5",
                    "EndpointID": "4c25273ed065481b657a6b4878f81d5edcd6d82054d34a5fb197908f75765a3c",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null
                }
            }
        }
    }
]

进入正在运行的容器

外面平时使用的容器通常都是后台方式运行的

shell 复制代码
方式一(进入容器后开启一个新的终端)
docker exec -it 容器ID 要使用的shell
例:
docker exec -it bdc75926ba54 /bin/bash

方式二(进入容器正在执行的终端,不会启动新的进程)
docker attach 容器ID
例:
docker attach bdc75926ba54

从容器拷贝文件到主机上

shell 复制代码
docker cp 容器ID:容器内文件路径 目的主机路径
例: #将容器内的test.txt文件拷贝到主机的/root目录下
docker cp 6b627de01b09:/home/test.txt /root

查看docker的cpu状态

shell 复制代码
docker stats

练习

部署nginx
shell 复制代码
1、搜索镜像   search  (最好去docker hub网站上搜索)
2、下载镜像   pull
3、运行测试   run
shell 复制代码
docker pull nginx #拉取镜像

docker run -d --name nginx01 -p 3456:80 nginx
#以后台方式运行该镜像,起名为nginx01,3333为主机端口,80为容器地址
curl localhost:3456
#本机自测一下,可以通过


root@VM-4-17-ubuntu:/home/ubuntu# docker exec -it nginx01 /bin/bash
root@b4b82f2c26a3:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@b4b82f2c26a3:/# cd /etc/nginx
root@b4b82f2c26a3:/etc/nginx# ls
conf.d  fastcgi_params  mime.types  modules  nginx.conf  scgi_params  uwsgi_params
部署tomcat
shell 复制代码
#官方使用
docker run -it --rm tomcat:9.0 #用完即删,一般用于测试

#正常下载启动
docker pull tomcat #拉取镜像
docker run -d -p 3457:8080 --name tomcat01 tomcat
#和上面部署nginx一样,此时可以访问,但不是完整的(是一个阉割版)

root@VM-4-17-ubuntu:/home/ubuntu# docker exec -it tomcat01 /bin/bash
root@cd322dbdf282:/usr/local/tomcat# ls
bin  BUILDING.txt  conf  CONTRIBUTING.md  lib  LICENSE  logs  native-jni-lib  NOTICE  README.md  RELEASE-NOTES  RUNNING.txt  temp  webapps  webapps.dist  work
root@cd322dbdf282:/usr/local/tomcat# cd webapps   #应用一般放在这个webap ps文件夹中
root@cd322dbdf282:/usr/local/tomcat/webapps# ls   #但是webapps里面什么都没有
#里面没有完整的linux命令、没有webapps,因为他只提供最小可运行的环境
root@cd322dbdf282:/usr/local/tomcat# cd webapps.dist
root@cd322dbdf282:/usr/local/tomcat/webapps.dist# ls
docs  examples  host-manager  manager  ROOT
#可以看到webapps.dist文件夹下有内容,将这个里面内容拷贝到webapps目录下
root@cd322dbdf282:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@cd322dbdf282:/usr/local/tomcat# ls webapps
docs  examples  host-manager  manager  ROOT
#此时再次刷新网页,即可正常显示
部署ES+Kibana

es和kibana之间需要进行网络通信,首先要创建一个虚拟网络

shell 复制代码
docker network create es-net

部署es

shell 复制代码
#ES暴露的端口很多,ES很耗内存!!!,且ES的数据一般需要放置到安全目录挂载
#下载启动
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

#由于十分耗内存,内存小可能无法启动,这里使用-e参数修改环境配置
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
#docker stats 查看docker的cpu状态,可以发现内存很小了,
#curl localhost:9200 发现web页面也可以正常访问了

部署kibana(要于es的版本一致)

shell 复制代码
docker pull kibana:7.6.2 #用的国内的源,无法下载最新的
#启动(如果遇到Kibana server is not ready yet等一会就可以了)
docker run -d --name kibana02 -e ELASTICSEARCH_HOSTS=http://4554b397a6f3:9200 --net=es-net -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -p 5601:5601 kibana:7.6.2
#第一个-e是设置es的节点地址,如果用容器ID不好使就换成服务器ip
#将es的容器ID替换成服务器的ip也可以

成功进入

镜像原理

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需的所有内容,包括代码、库、环境变量、配置文件。

加载原理

联合文件系统(UnionFS):一种分成、轻量级且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下

docker的镜像是机械上由一层一层的文件系统组成,这种层级文件系统被称为联合文件系统。

bootfs(boot file system):是docker镜像的最底层,主要包含boot加载器和kernel内核,而boot加载器用来引导加载kernel。

linux启动时会加载bootfs系统,加载完之后内存的使用权就由bootfs交给内核了,系统此时也会卸载bootfs

rootfs(root file system) :是在bootfs之上一层的文件系统,包含linux系统中的dev/ /proc /bin /etr标准目录和文件。是一个小型的虚拟环境

rootfs就是各种操作系统的发行版,如centos、bunut等

分层原理

所有docker镜像都起始于一个基础镜像层,当修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

例如下载镜像时候,第一层相同,直接复用,其他几层分层下载

afb6ec6fdc1c: Already exists 
608641ee4c3f: Pull complete 
668ab9e1f4bc: Pull complete 
78a12698914e: Pull complete 
d056855f4300: Pull complete 
618fdf7d0dec: Pull complete 

举一个例子:例如创建一个ubuntu镜像,这是该镜像的第一层。如果添加了一个python环境包,就会在基础镜像层上创建第二个镜像层。如果继续添加一个补丁,就好创建第三个镜像层。

在额外添加镜像时,镜像始终保持当前镜像的组合。

例如:镜像包含了来自两个镜像层的6个文件,每个镜像层有三个文件。

如果变成三层镜像,其中文件7是文件5的更新版本,上层镜像层中的文件会覆盖底层镜像层中的文件。

所有镜像层合并,对外统一视图仍为6个文件

docker镜像都是只读的,当容器启动时,一个新的可写层被加=加载到镜像的顶部。(这一层被称为容器层,容器层之下都被称为镜像层)!

commit镜像
shell 复制代码
docker commit 提交容器成为一个新副本
#与git类似
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名[:tag]

例:

shell 复制代码
# 1、启动一个默认的tomcat
docker run -d -p 8080:8080 tomcat
# 2、这个默认的tomcat是没有webapps应用,官方的镜像默认webapps下面是没有文件的
docker exec -it 容器id
# 3、拷贝文件进去
cp -r webapps.dist/* webapps
# 4、将操作过的容器通过commit提交为一个镜像。
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="jess" -m="add webapps app" 容器id tomcat02:1.0

容器数据卷

场景:如果数据存储在容器中,删除容器数据就会被删除。

需求:数据可以持久化。例如:mysql的数据保存在本地

容器之间都数据共享技术。docker产生的数据同步到本地,这就是卷技术。本质上就是目录的挂载,将容器中的目录挂载到我们的主机系统上。

总结:容器的同步操作和持久化,容器间也可以数据共享。

使用数据卷

主要使用-v参数

shell 复制代码
docker run -it --name centos01 -v 主机目录:容器目录 容器ID 使用的shell

这里以centos镜像为例

shell 复制代码
docker run -it --name centos01 -v /home/test:/home centos /bin/bash

此时主机的/home/test目录与容器中的/home目录中的所有内容都互通。

无论在哪一端修改,里面的内容都会同步

使用inspect命令查看是否挂载成功

shell 复制代码
#docker inspect 14309fc52d5d
回显内容包括以下内容即挂载成功
"Mounts": [
            {
                "Type": "bind",
                "Source": "/root/test",
                "Destination": "/home",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

前面说的修改nginx配置文件很麻烦,每次都要进入容器内部才能修改。

但是通过-v容器卷挂载,在容器外部提供一个映射路径,就可以解决这个问题了。

实战:mysql同步数据
shell 复制代码
 #启动mysql时需要设置密码
docker run -d --name mysql01 -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql

使用Navicat连接,这里的主机名改为自己的服务器ip即可。

连接成功,并新建一个数据库,名为test

可以看到在主机的/home/docke/data文件夹下也生成了test文件

将mysql容器删除,再次查看该文件夹,发现文件仍存在。这就达到了使用容器数据卷挂载的目的。

具名挂载、匿名挂载
shell 复制代码
匿名挂载:当使用-v参数不指定主机目录时
docker run -d --name nginx03 -P -v /etc/nginx nginx
#-P随机映射端口
具名挂载:卷名/容器内目录  #这里的卷名不带路径'/'
docker run -d -P --name nginx04 -v juming-nginx:/etc/nginx nginx
docker volume ls #查看所有的卷

可以看到这两个卷,那么这两个卷在哪里呢

shell 复制代码
docker volume inspect juming-nginx #查找卷的路径
#可以看到,不指定目录的情况下,都会保存在/var/lib/docker/volumes目录下
[
    {
        "CreatedAt": "2024-11-20T19:11:24+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]
shell 复制代码
总结:
-v 容器内路径           #匿名挂载
-v 卷名:容器内路径      #具名挂载(比指定路径少一个/)
-v /主机路径:容器内路径 #指定路径挂载
shell 复制代码
拓展:还可以通过-v参数设置读写权限,但是一旦设置之后就不能修改
ro #readonly只读
rw #readwrite可读可写
docker run -d -P --name nginx04 -v juming-nginx:/etc/nginx:ro nginx  #只读
docker run -d -P --name nginx04 -v juming-nginx:/etc/nginx:rw nginx  #可读可写
如果看到ro,说明这个路径只能通过主机操作,容器内无法操作
容器间数据同步

使用--volumes-from参数实现容器间数据共享(可以当作备份、拷贝)

shell 复制代码
docker run -it --name docker01 centos_plus /bin/bash

docker run -it --name docker02 --volumes-from docker01 centos_plus /bin/bash

docker run -it --name docker03 --volumes-from docker02 centos_plus /bin/bash

操作其中一个容器,其他容器也会随之改变。

如果删除其中一个容器,其他容器中的文件还会在,数据卷容器的生命周期一直会持续到没有容器使用为止。

如果持久化到本地,本地的数据是不会删除的。

Dockerfile

简介及构建DockerFile方式

DockerFile就是用来构建docker镜像的构建文件(可以看作命令脚本,通过这个脚本可以生成镜像)

基础知识:

1、每个保留关键字(指令)都要大写

2、执行命令从上到下执行

3、#表注释

4、每个指令都会创建提交一个新的镜像层并提交

DockerFile:构建文件,定义了一切的步骤、源代码

DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品

Docker容器:容器就是镜像运行起来提供服务器

构建步骤

1、编写DockerFile文件

2、docker build构建镜像

3、docker run运行镜像

4、docker push发布镜像

dockerfile 复制代码
#一个小例子,命名为file1
FROM centos

VOLUME ["volume01","volume02"]  #匿名挂载

CMD echo "----end----"

CMD /bin/bash
shell 复制代码
docker build -f file1 -t centos_test .
-f参数 指定文件
-t参数 指定生成的镜像名
DockerFile指令
dockerfile 复制代码
FROM        #基础镜像,一切从这里开始构建
MAINTAINER  #镜像是谁写的
RUN         #镜像构建时需要运行的命令
ADD  		#添加内容。以构建tomcat镜像为例,这是tomcat压缩包
WORKDIR     #镜像的工作目录
VOLUME		#挂载的目录
EXPOSE      #暴露端口配置 相当于-p
CMD			#指定这个容器启动时要运行的命令,但只有最后一个会生效,可以被替代
ENTRYPOINT  #与CMD类似,但可以追加命令
ONBUILD     #当构建一个被继承的DockerFile时,就会运行ONBUILD指令
COPY		#类似ADD,将文件拷贝到镜像中
ENV			#构建时,设置环境变量  -e

CMD与ENTRYPOINT的区别

CMD

dockerfile 复制代码
#dockerfile文件
FROM centos:7
CMD ["ls","-a"]

build成功之后,run该容器时会执行该命令。

shell 复制代码
docker run 3608c6aac6fd -l     #会报错
docker run 3608c6aac6fd ls -al #会执行最后一个命令ls -al
docker run 3608c6aac6fd pwd    #只会执行pwd命令

说明CMD命令不能拼接命令,且只能执行最后一个命令(最后的命令会覆盖前面的命令)

ENTRYPOINT

dockerfile 复制代码
FROM cnetos:7
ENTRYPOINT ["ls","-a"]

build成功之后

shell 复制代码
docker run 6beb6f712117 -l #会执行这两个参数,即ls -al

说明ENTRYPOINT可以进行拼接命令

实战:构建自己的centos

Docker Hub中绝大多数镜像都是在FROM scratch这个基础镜像之上构建的,然后配置需要的软件和配置来构建。

注意dockerifle文件中,最好不要有注释,构建之后会很难看

dockerfile 复制代码
#编写dockerfile文件内容
FROM centos:7
MAINTAINER clockwise  #声明作者

ENV MYPATH /usr/local 
WORKDIR $MYPATH   #定义工作目录,进入直接会进入该目录
#这里换成阿里云的centos7镜像
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
#基础镜像命令也是不全的,这里进行安装vim和ifconfig命令
RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80  #暴露80端口

CMD echo $MYPATH
CMD echo "end"
CMD /bin/bash
shell 复制代码
#通过dockerfile构建镜像
docker build -f file1 -t mycentos:1.0 .
shell 复制代码
#运行镜像
docker run -it mycentos:1.0

进入之后会发现当前的目录就是上面定义的/usr/local

vim命令和ifconfig命令也可以使用。

shell 复制代码
#使用history命令查看变更历史
docker history 6bc730024d72

可以看到镜像的制作过程命令(说明命令是一条一条进行编译的)

实战:构建自己的tomcat镜像

1、首先准备镜像文件:tomacat压缩包和jdk压缩包

2、构建DockerFile,官方命名为Dockerfile,使用该命名就不需要指定路径了

dockerfile 复制代码
FROM centos:7
MAINTAINER clockwise
#通过ADD命令添加会自动解析
ADD jdk-8u201-linux-x64.tar.gz /usr/local/    
ADD apache-tomcat-9.0.12-src.tar.gz /usr/local/

RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_201
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.12-src
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.12-src
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.12-src/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.12/bin/logs/catalina.out
shell 复制代码
docker run -d -p 9090:8080 --name mytomcat -v /root/tomcat_test/test:/usr/local/apache-tomcat-9.0.12-src/webapps/test -v /root/tomcat_test/logs:/usr/local/apache-tomcat-9.0.12-src/logs smalltomcat

docker网络

理解docker 0

这里服务器内网ip为192.168.12.87。

shell 复制代码
root@hcss-ecs-2214:/# 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether fa:16:3e:a5:09:54 brd ff:ff:ff:ff:ff:ff
    inet 192.168.12.87/20 brd 192.168.15.255 scope global dynamic noprefixroute eth0
       valid_lft 315275508sec preferred_lft 315275508sec
    inet6 fe80::f816:3eff:fea5:954/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:e2:20:15:88 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:e2ff:fe20:1588/64 scope link 
       valid_lft forever preferred_lft forever
       
#1、lo为本机回环地址
#2、为服务器内网地址
#3、docker0地址

这里使用tomcat进行测试,由于tomcat镜像过于精简,不带iproute2功能,这里需要自己新建一个镜像

dockerfile 复制代码
#Dockerfile文件
FROM tomcat:latest
RUN apt update && apt install -y iproute2  #添加ip addr命令
RUN apt install -y iputils-ping  #添加ping命令
shell 复制代码
docker build -t newtomcat  #自己新建一个镜像起名为newtomcat

测试主机和容器之间的通信:

shell 复制代码
docker run -d -P --name tomcat01 newtomcat

docker exec -it tomcat01 ip addr

可以看到一个是回环地址127.0.0.1,一个是eth0@if123(docker自动分配的地址)的地址172.17.0.2

主机ping这个ip,发现可以Ping通。进入容器ping主机ip,发现也可以ping通。

说明主机和docker之间可以进行通信。

原理:

当启动docker容器时,docker会自动给docker容器分配一个ip,只要安装了docker就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术

当只有一个容器的时候,在主机使用ip add命令查看网卡

可以看到主机中有一个·vethbdd6727@if122

此时,再建立一个容器命名为tomcat02,再去查看主机网卡

发现多了一个vethf99a830@if124

这说明docker容器生成的网卡都是一对一对的。
evth-pair就是一对的虚拟设备接口,他们是成对出现的,一段连接着协议,一段彼此相连。
由于这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备
OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术

测试容器之间的通信:

shell 复制代码
使用tomcat02去ping tomcat01的ip
docker exec -it tomcat02 ping 172.17.0.2
#可以ping通的

tomcat01和tomcat02都是共用一个路由器--docker0

所有容器不指定网络的情况下,都是由docker0给容器分配一个默认可用的ip。

虚拟网络接口的转发效率高

通过--link,不通过网络、地址,容器之间通过容器名ping通。(--link只有构建容器时才可以使用)

shell 复制代码
docker exec -it tomcat02 ping tomcat01
#ping: tomcat01: Name or service not known

docker run -d -P --name tomcat03 --link tomcat02 newtomcat
docker exec -it tomcat03 ping tomcat02
#tomcat03可以ping通tomcat02
#但是tomcat02不能ping通tomcat03

那么如何才能让tomcat02ping通tomcat03?

可以通过docker network inspect查看一下bridge中的网卡信息

shell 复制代码
root@hcss-ecs-2214:~# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0d149ac9fdda   bridge    bridge    local
d5280ca25d4b   host      host      local
6855cd3d7f31   none      null      local
root@hcss-ecs-2214:~# docker network inspect 0d149ac9fdda
[
    {
        "Name": "bridge",
        "Id": "0d149ac9fddafe29418226287d8450e5016bb5a120a57f0a3726f5dbca5079e6",
        "Created": "2024-11-20T18:01:30.899264891+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "37bcfb2c3a5ee8a6990d962654fd928803d7dcca75ce95019101875242116e44": {
                "Name": "tomcat03",
                "EndpointID": "9c295d4859973080e89c835997fa3f5afa592c22028bc71509cb3a044a8bf202",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            },
            "4e3107cadc5e7984d7cb500b9a3d6dd121d597a35ba3c03ed48386379072db59": {
                "Name": "tomcat01",
                "EndpointID": "b10e9a3b00226b66013239f18121f0f1c71f317d84eee0f923ffbe5a5c0c9eaf",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "65aca855c46bc57e730842cff5a1cabb2ca14633b8ddc20536e6ad9ee69b13b2": {
                "Name": "tomcat02",
                "EndpointID": "0e81426b6c74065dd90036b6d9911f8b6cf136d653625144ca2e320543527ce8",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.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": {}
    }
]

然后查看tomcat03的hosts文件可以看到在tomcat03本地已经配置了tomcat02的地址

shell 复制代码
docker exec -it tomcat03 cat /etc/hosts
root@hcss-ecs-2214:~# 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
172.17.0.3      tomcat02 65aca855c46b
172.17.0.4      37bcfb2c3a5e

由于docker0不支持容器名访问等问题,因此出现了自定义网络

自定义网络
shell 复制代码
docker network --help查看docker网络相关命令

查看所有docker网络

shell 复制代码
docker network ls 
root@hcss-ecs-2214:~# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0d149ac9fdda   bridge    bridge    local
d5280ca25d4b   host      host      local
6855cd3d7f31   none      null      local

桥接模式:

bridge:桥接docker

none:不配置网络

host:和宿主机共享网络

container:容器内网络连通(用的少)

shell 复制代码
#平时启动容器时,默认使用--net bridge
docker run -d -P --name tomcat01 newtomcat
docker run -d -P --name tomcat01 --net bridge newtomcat

#自定义网络
docker network create --help #查看相关命令
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
#--driver bridge 桥接模式
#--gateway参数设置网关,家庭路由器默认就是192.168.0.1

#使用inspect命令查看
docker network inspect mynet

可以看到已经创建成功

shell 复制代码
#启动两个容器测试一下
docker run -d -P --name tomcat01 --net mynet newtomcat
docker run -d -P --name tomcat02 --net mynet newtomcat

inspect查看一下mynet,可以看到成功指定该网络

shell 复制代码
#现在使用容器名和ID都可以互相ping通过了
docker exec -it tomcat01 ping tomcat02 
网络连通
shell 复制代码
docker run -d -P --name tomcat-net-01 --net mynet tomcat-net
docker run -d -P --name tomcat-net-02 --net mynet tomcat-net

docker run -d -P --name tomcat-01 tomcat-net
docker run -d -P --name tomcat-02 tomcat-net

测试tomcat-01和mynet打通(tomcat-02同理)

shell 复制代码
docker network connect mynet tomcat-01
然后使用inspect查看
docker network inspect mynet

发现成功将tomcat-01放到mynet网络下。(即一个容器两个地址 )

之后在该mynet网络下的容器就可以互相通信了。

实战:Redis集群部署
shell 复制代码
#创建redis网卡
docker network create redis --subnet 172.38.0.0/16

#通过脚本创建(之间复制到命令行即可)
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
#执行完可以看到在/mydata/redis目录下生成了6个node-目录

docker run -p 6371:7379 -p 16371:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
#这是第一个,以此类推,写六个
docker run -p 6371:7379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
#这是第二个
docker run -p 6372:7379 -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; \

进入第一个容器(这里没有/bin/bash,要用/bin/sh)

shell 复制代码
docker exec -it redis-1 /bin/sh
#创建集群
redis-cli --cluster create 172.38.0.11:6371 172.38.0.12:6372 172.38.0.13:6373 172.38.0.14:6374 172.38.0.15:6375 172.38.0.16:6376 --cluster-replicas 1
shell 复制代码
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
docker run -p 6371:7379 -p 16371: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

Docker Compose

Docker-Compose是Docker官方的开源项目,用来实现对Docker容器集群的快速编排。

通过yml文件(yaml也是一样的,没有任何区别)配置应用程序需要的所有服务。

使用步骤:

1、使用Dockerfile定义的应用程序环境

2、使用docker-compose.yml定义构成应用程序的服务(使他们在隔离环境中一起运行)

3、执行docker-compose up命令来启动运行整个应用程序

相关推荐
Ronin-Lotus15 分钟前
上位机知识篇---ROS2命令行命令&静态链接库&动态链接库
学习·程序人生·机器人·bash
超级阿飞36 分钟前
利用Kubespray安装生产环境的k8s集群-排错篇
docker·容器·kubernetes
Kasper01211 小时前
认识Django项目模版文件——Django学习日志(二)
学习·django
Amctwd2 小时前
【Docker】私有Docker仓库的搭建
spring cloud·docker·eureka
索然无味io2 小时前
XML外部实体注入--漏洞利用
xml·前端·笔记·学习·web安全·网络安全·php
一弓虽2 小时前
java基础学习——jdbc基础知识详细介绍
java·学习·jdbc·连接池
五味香3 小时前
Java学习,List 元素替换
android·java·开发语言·python·学习·golang·kotlin
云游的二狗4 小时前
【VMWare Workstation 17】安装Debian 12.8DVD
运维·docker·debian
嘿嘿4 小时前
Grafana 快速搭建go-metrics 仪表盘备忘
后端·docker·go
cv-daily4 小时前
通过docker overlay2目录名查找容器名和容器ID
运维·docker·容器