1,概述
虚拟化技术:容器(应用层)、虚拟机(软件层)
docker:隔离,镜像占用资源小,秒级
vm:GB级
docker基于Go语言开发的
2,docker基础
2.1,架构
图1 架构图
镜像(image):
docker镜像就像一个模板,例如:redis镜像》run》redis容器(对外提供服务)
一个镜像可以创建多个容器!!!
容器(container):
利用容器技术独立运行一个或者一组应用,通过镜像创建
启动、停止、删除
仓库(repository):类似github、gitlab代码仓库
存放镜像的地方:公有仓库和私有仓库
2.2,安装docker
图2 查看自己的服务器内核情况
图3 通过数据库
# 1,先删除老版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 2,设置仓库
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
# 3,直接进入阿里云docker加速镜像设置国内的镜像地址(https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://g8kfoxhi.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 4,安装docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 5,查看是否安装成功(执行hello-world程序)
docker search hello-world
docker pull hello-world
docker run hello-world
# 其他 docker的资源路径
/var/lib/docker
# 如果想要协助该资源则可以直接
rm -rf /var/lib/docker
2.3,docker hello-world启动流程
图4 docker镜像启动流程
2.4,底层原理
docker是怎么工作?
docker是一个Client-Server结构的系统,docker的守护进程运行在主机上。通过socket从客户端访问!
图5 docker底层
docker为什么比虚拟机快?
1,docker只在应用层进行抽象
2,docker(秒级别)利用的是宿主机的内核,vm(分钟级别)需要Guest OS
所以说,新建一个容器的时候,docker不需要像虚拟机那样重新加载一个操作系统内核,避免引导!
图6 虚拟机与docker架构区别
图7 docker与虚拟机的性能差异
备注:当前docker也支持全平台
2.5,docker常用命令
帮助命令
docker version # 显示版本
docker info # 系统信息
docker [命令] --help # 帮忙命令
镜像命令
docker images # 查看所有镜像
REPOSITORY
搜索
docker search [namelike]
Options:
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print search using a Go template
--limit int Max number of search results (default 25)
--no-trunc Don't truncate output
下载
docker pull [name] # 如果不写tag,默认就是latest
Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Pull an image or a repository from a registry
Options:
-a, --all-tags Download all tagged images in the repository
--disable-content-trust Skip image verification (default true)
--platform string Set platform if server is multi-platform capable
-q, --quiet Suppress verbose output
例如:
docker pull mysql
docker pull docker.io/library/mysql:latest # 等价
删除镜像
docker rmi -f ${docker images -qa} # 删除所有
docker rmi -f [镜像id 镜像id ...] # 删除单个或多个
容器命令
docker run [可选参数] image
--name #容器名称
-d #后台方式运行
-it #使用交换方式运行,进入容器查看内容
-p #指定容器的端口 例如 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-P #随机一个端口
# 测试centos
[root@iZbp1jbs6mikemed8a6mooZ:~]# docker run -it centos /bin/bash
[root@9f7972f753e0 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@9f7972f753e0 /]# exit
列出所有运行的容器
docker ps #显示所有正在运行的容器
docker ps -a #显示所有容器
docker ps -n #显示n个
docker ps -q #只显示id
退出容器
exit #直接容器停止退出
ctrl +p +q
删除容器
docker rm [id] #只能删除未运行
docker rm -f [id] #强制删除所有容器
docker rm -f ${docker ps -aq} #强制删除所有容器
docker ps -a -q|xargs docker rm #删除所有容器
启动和停止容器
docker start [id]
docker restart [id]
docker stop [id]
docker kill [id] #强制停止
常用的其他命令
docker run -d [name] # 后台启动
# 常见的坑:docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
日志
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
-n, --tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
# 样例
docker logs -f -t --tail 100 ba8c6c794fae # 查看最近的100条日志
docker logs -ft ba8c6c794fae # 查看最近的100条日志
docker run -d centos /bin/sh -c "while true;do echo wanyu;sleep 1;done"
查看容器中的进程信息
[root@iZbp1jbs6mikemed8a6mooZ:~]# docker top acba17f136c3
UID PID PPID C STIME TTY TIME CMD
root 859775 859753 0 Nov29 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 859834 859775 0 Nov29 ? 00:00:00 nginx: worker process
systemd+ 859835 859775 0 Nov29 ? 00:00:00 nginx: worker process
查看docker中容器的状态
docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
1196c69ed611 webdav-aliyundriver 1.86% 404.3MiB / 7.429GiB 5.32% 151MB / 144MB 49.2kB / 152kB 48
6cde4548c0a8 consul 0.15% 22.07MiB / 7.429GiB 0.29% 289kB / 8.53MB 12.8MB / 478MB 10
3fe6fe9b36e0 zipkin 0.18% 262.2MiB / 7.429GiB 3.45% 190kB / 4.79MB 58.7MB / 86kB 48
acba17f136c3 nginx 0.00% 5.898MiB / 7.429GiB 0.08% 109kB / 118kB 3.96MB / 0B 5
ba8c6c794fae rabbitmq 0.17% 111.6MiB / 7.429GiB 1.47% 1.42MB / 4.9MB 8.44MB / 94.2kB 25
3457dfb68671 postgres 0.00% 28.11MiB / 7.429GiB 0.37% 671kB / 533kB 14.7MB / 249MB 7
1ba5c5143b3c redis-test 0.27% 7.52MiB / 7.429GiB 0.10% 468kB / 947kB 3.74MB / 24.6kB 5
b4e6a28e2ec3 nexus 0.64% 1.572GiB / 7.429GiB 21.17% 5.06MB / 18.5MB 6.34MB / 308MB 106
查看容器的信息
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on Docker objects
Options:
-f, --format string Format the output using the given Go template
-s, --size Display total file sizes if the type is container
--type string Return JSON for specified type
点击查看docker inspect [id]
[root@iZbp1jbs6mikemed8a6mooZ:~]# docker inspect ba8c6c794fae [ { "Id": "ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9", "Created": "2021-11-15T01:00:05.26730652Z", "Path": "docker-entrypoint.sh", "Args": [ "rabbitmq-server" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 245415, "ExitCode": 0, "Error": "", "StartedAt": "2021-11-28T14:55:17.581464973Z", "FinishedAt": "2021-11-28T14:55:05.650833939Z" }, "Image": "sha256:a4eb038c2ecb80281487ebbdf40938bbc05ebf976df23ff664dec072aad5546a", "ResolvConfPath": "/var/lib/docker/containers/ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9/resolv.conf", "HostnamePath": "/var/lib/docker/containers/ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9/hostname", "HostsPath": "/var/lib/docker/containers/ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9/hosts", "LogPath": "/var/lib/docker/containers/ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9/ba8c6c794faed04c6d72d5fe44ee81856ee786175325c33bb99899cab2e54ea9-json.log", "Name": "/rabbitmq", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "docker-default", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "15672/tcp": [ { "HostIp": "", "HostPort": "15672" } ], "5672/tcp": [ { "HostIp": "", "HostPort": "5672" } ] }, "RestartPolicy": { "Name": "always", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "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", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": null, "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" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/e9c85a92ac0b77f7cde594a77161a09da13466171602e9d25523f5d19b3b16eb-init/diff:/var/lib/docker/overlay2/35fd3bcf07f11dcb9411055f9a769cd2c200409f7e5ad7b3bb86310ada66ddaf/diff:/var/lib/docker/overlay2/e0bcd1bcb4c5255bb60b96009ded735001428bd7192eedce421579baad70686d/diff:/var/lib/docker/overlay2/45572bc4887aa6081a5020c0d873ca265db119543390ed1a8c972297246f4774/diff:/var/lib/docker/overlay2/bdeca6a433e28a38697efcf02f2ef67e1f5b7ac6cde5e5969d7c9390da7c9000/diff:/var/lib/docker/overlay2/7d797d0cbba46fcddb2ba1ab7e22332f4470019a41303a7c7d8e586a4dea5c6b/diff:/var/lib/docker/overlay2/500b8c37f7bbf6b8d392e4cd9a1317366d8323a689a115d2bce96b19a8e14c27/diff:/var/lib/docker/overlay2/a58f0d5dd6ece8510c32fab5a508a285888a3e8a1a4bca1c164ae488a507d0dd/diff:/var/lib/docker/overlay2/9c2252ca7416153ddc579aeff11f7195e21d7a0db20b1f74f6d73a0d98c7dbd5/diff:/var/lib/docker/overlay2/62a25cea110c9408ec62c08b3de6e4121aea0b60ff18dd32575b33898a36fece/diff", "MergedDir": "/var/lib/docker/overlay2/e9c85a92ac0b77f7cde594a77161a09da13466171602e9d25523f5d19b3b16eb/merged", "UpperDir": "/var/lib/docker/overlay2/e9c85a92ac0b77f7cde594a77161a09da13466171602e9d25523f5d19b3b16eb/diff", "WorkDir": "/var/lib/docker/overlay2/e9c85a92ac0b77f7cde594a77161a09da13466171602e9d25523f5d19b3b16eb/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "volume", "Name": "45692529f011e22ffe3b097f4fea2ba54dc305635d4ea056b422143190a684e7", "Source": "/var/lib/docker/volumes/45692529f011e22ffe3b097f4fea2ba54dc305635d4ea056b422143190a684e7/_data", "Destination": "/var/lib/rabbitmq", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], "Config": { "Hostname": "rabbitmqhost", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "15672/tcp": {}, "15691/tcp": {}, "15692/tcp": {}, "25672/tcp": {}, "4369/tcp": {}, "5671/tcp": {}, "5672/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "RABBITMQ_DEFAULT_USER=admin", "RABBITMQ_DEFAULT_PASS=rabbitmq", "PATH=/opt/rabbitmq/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "OPENSSL_VERSION=1.1.1l", "OPENSSL_SOURCE_SHA256=0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1", "OPENSSL_PGP_KEY_IDS=0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D", "OTP_VERSION=24.1.5", "OTP_SOURCE_SHA256=a6b28da8a6382d174bb18be781476c7ce36aae792887dc629f331b227dfad542", "RABBITMQ_DATA_DIR=/var/lib/rabbitmq", "RABBITMQ_VERSION=3.9.9", "RABBITMQ_PGP_KEY_ID=0x0A9AF2115F4687BD29803A206B73A36E6026DFCA", "RABBITMQ_HOME=/opt/rabbitmq", "RABBITMQ_LOGS=-", "HOME=/var/lib/rabbitmq", "LANG=C.UTF-8", "LANGUAGE=C.UTF-8", "LC_ALL=C.UTF-8" ], "Cmd": [ "rabbitmq-server" ], "Image": "rabbitmq", "Volumes": { "/var/lib/rabbitmq": {} }, "WorkingDir": "", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "0391b2e391560ec3c1411dbb8a9c2b3c554e7054d4a7eb7043f5ec9d9527dd5a", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "15672/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "15672" }, { "HostIp": "::", "HostPort": "15672" } ], "15691/tcp": null, "15692/tcp": null, "25672/tcp": null, "4369/tcp": null, "5671/tcp": null, "5672/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "5672" }, { "HostIp": "::", "HostPort": "5672" } ] }, "SandboxKey": "/var/run/docker/netns/0391b2e39156", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "48435f72b1cb9c41ab511f61fdd7a77133af1585b1c63e171dda4c41dc9025c0", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.6", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:06", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "2b8b92432a38ddbe5b410f687d5ca9dd37372d552895d571564cadd8b0b93134", "EndpointID": "48435f72b1cb9c41ab511f61fdd7a77133af1585b1c63e171dda4c41dc9025c0", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.6", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:06", "DriverOpts": null } } } } ]
进入正在运行的容器
# 通常使用后台执行,进入容器中修改一些配置
docker exec -it [id] /bin/bash # 进入容器后开启新的终端
docker attach [id] # 进入容器正在执行的终端,不会启动新的终端,退出会关闭!!
文件拷贝
# 将容器内的文件拷贝到外部
docker cp 752b54e35d4d:/home/wanyu.java /home
# 拷贝是手动过程,未来使用-v卷的集合可以实现数据打通
3,练习部署
3.1,es+kibana
难点
1,暴露的端口很多
2,特别耗费内存
3,数据一般需要放置到安全目录!挂载
启动命令
# --net somenetwork ? 网络配置
docker network create somenetwork
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag
# elasticsearch特别卡顿
# 直接访问9200端口查看
点击查看http://ip:9200/
{ "name" : "ab061e45a753", "cluster_name" : "docker-cluster", "cluster_uuid" : "FubYpwPzT8iksfByFF-i_g", "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" }
# 增加内存限制
docker run -d --name elasticsearch2 --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:tag
点击查看docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9620da899a40 elasticsearch2 0.20% 219.4MiB / 7.429GiB 2.88% 876B / 0B 164kB / 156kB 36 1196c69ed611 webdav-aliyundriver 0.14% 404.5MiB / 7.429GiB 5.32% 155MB / 147MB 49.2kB / 152kB 48 6cde4548c0a8 consul 0.26% 21.91MiB / 7.429GiB 0.29% 289kB / 8.53MB 12.9MB / 479MB 10 3fe6fe9b36e0 zipkin 3.13% 261.7MiB / 7.429GiB 3.44% 190kB / 4.79MB 58.8MB / 86kB 49 acba17f136c3 nginx 0.00% 6.023MiB / 7.429GiB 0.08% 110kB / 119kB 5.82MB / 0B 5 ba8c6c794fae rabbitmq 0.18% 112MiB / 7.429GiB 1.47% 1.44MB / 5.44MB 8.93MB / 94.2kB 25 3457dfb68671 postgres 0.00% 28.41MiB / 7.429GiB 0.37% 671kB / 533kB 14.8MB / 250MB 7 1ba5c5143b3c redis-test 0.15% 7.656MiB / 7.429GiB 0.10% 470kB / 973kB 4.07MB / 24.6kB 5 b4e6a28e2ec3 nexus 0.53% 1.572GiB / 7.429GiB 21.16% 5.06MB / 18.5MB 6.35MB / 309MB 106
直接使用外部的ip地址连接也可以
3.2,部署portainer
docker run -d -p 8082:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
直接访问ip:8082即可
具体可参考链接3
注意:不要贸然放开2375 端口,除非你想被docker中的挖矿病毒入侵!!!
4,docker镜像原理
镜像就是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,包含运行某个软件所需的所有内容(代码、运行时、库、环境变量和配置文件)。
4.1,UnionFS(联合文件系统)
一种分层、轻量级且高性能的文件系统,支持对文件系统的修改作为一次提交来层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unitseveral directories into a single virtual)。Union文件系统 是docker镜像基础,镜像可以通过分层来进行继承,基于基础镜像(没有父级镜像),可以制作各种文件具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载回波各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
4.2,docker镜像加载原理
docker镜像用我自己的话说就是盖楼房一样,一层一层的搭建,先是地基(bootfs)、一层(rootfs)、二层、......n层。-万雨
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就是各种不同的操作系统发行版。
核心点:由于unionFS的缘故,docker上层的东西可以共用下层相同的文件,所以使得docker很轻巧!!!
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用host的kernel,自己只需要提供rootfs即可。由此可见对于不同的Linux发行版,bootfs基本上都是一致的,rootfs会有差别,因为不同的发行版可以公用bootfs。
虚拟机是分钟级别,容器是秒级!
4.3,分层原理
下载一个镜像里面是由很多层(layer)的,分层下载、共有!
docker image inspect redis #注意其中的layers
点击查看docker image inspect redis
[ { "Id": "sha256:02c7f2054405dadaf295fac7281034e998646996e9768e65a78f90af62218be3", "RepoTags": [ "redis:latest" ], "RepoDigests": [ "redis@sha256:e595e79c05c7690f50ef0136acc9d932d65d8b2ce7915d26a68ca3fb41a7db61" ], "Parent": "", "Comment": "", "Created": "2021-09-03T13:26:48.395038582Z", "Container": "3627b30c1a4cf3ef703e0516beee6428efe1b08a5314f5f106b84250635809cb", "ContainerConfig": { "Hostname": "3627b30c1a4c", "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.5", "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.5.tar.gz", "REDIS_DOWNLOAD_SHA=4b9a75709a1b74b3785e20a6c158cab94cf52298aa381eea947a678a60d551ae" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"redis-server\"]" ], "Image": "sha256:332cd8bceec776c2152877041d9e60cbaf4ba95504335e888311bcc1444155a7", "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.5", "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.5.tar.gz", "REDIS_DOWNLOAD_SHA=4b9a75709a1b74b3785e20a6c158cab94cf52298aa381eea947a678a60d551ae" ], "Cmd": [ "redis-server" ], "Image": "sha256:332cd8bceec776c2152877041d9e60cbaf4ba95504335e888311bcc1444155a7", "Volumes": { "/data": {} }, "WorkingDir": "/data", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": null }, "Architecture": "amd64", "Os": "linux", "Size": 105408201, "VirtualSize": 105408201, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/e85c9d4bafcf1c40dcf4c7267ca818d50c2f45431a0d1653a66bb68a2dca9137/diff:/var/lib/docker/overlay2/89f9dfc82617f584b5c188baed7551df3fbf3b3bd63a80304d10052e31e8fb84/diff:/var/lib/docker/overlay2/35ec30c65570785f546b2f7bee4c01b0de4ab167ec80d9be38b0a0b2828e5723/diff:/var/lib/docker/overlay2/94e27980d165ce69590d62121ae8e0bb3a10a0ee0964a1e3b0e6d006731b8535/diff:/var/lib/docker/overlay2/424f20b09e163cec1a6802233c76cdf1c5c0e46c32acec0dcf7aa4c9f8efd5c4/diff", "MergedDir": "/var/lib/docker/overlay2/25abbc429add8302f431fdbefb3dd5b55370129f5de3a53f450aa9ea10dfc47b/merged", "UpperDir": "/var/lib/docker/overlay2/25abbc429add8302f431fdbefb3dd5b55370129f5de3a53f450aa9ea10dfc47b/diff", "WorkDir": "/var/lib/docker/overlay2/25abbc429add8302f431fdbefb3dd5b55370129f5de3a53f450aa9ea10dfc47b/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:d000633a56813933cb0ac5ee3246cf7a4c0205db6290018a169d7cb096581046", "sha256:bdad86443e47c5665683ac41c1f24f28479d830d7e3cc47d0a337ee5166c7714", "sha256:6a7992ac480029d82b7dbb757d16fe5d023aa283ed32b52267cd1fe9e6b73c49", "sha256:be43d2475cf809c0f2ec31950e849d0f888f3121970fd99196a11a903f8c3820", "sha256:be5818ef2907adfe19be14bf66647b5fb5a2029143f9297f8ce1ff1fd1d35753", "sha256:c54e0c16ea22fa873c12f6a7f3fb4e021bb58d67c292156a6ce6e08637458b7c" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ]
4.4,commit镜像
docker commit 提交一个容器为新的副本
# 命令和git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
实战测试
# 1,启动一个默认的Tomcat
# 2,发现这个默认的Tomcat是没有webapps应用,镜像
docker pull tomcat # 下载Tomcat镜像
docker run -d -p 8080:8080 tomcat # 后台模式运行
docker exec -it [id] /bin/bash # 进入操作台
# 3,将自己的文件拷贝进去
cd /usr/local/tomcat
cp -r webapps.dist/* webapps
# 4,将改动后的文件commit为一个镜像
查看8080端口页面
将上述修改后的镜像重新打包!
# 使用docker inspect [镜像id] 查看原始镜像layer和重新提交的layer数据差异!
5,容器数据卷
5.1,命令
docker的理念是将应用和环境打包成一个镜像!(但是,数据也打包成镜像就不太好吧!数据丢失!)
容器之间可以有一个数据共享技术!docker容器中产生的数据,同步到本地!
卷技术-目录挂载,将容器中的目录挂载到Linux中的目录中!
1,容器持久化和同步操作;
2,容器间也可以进行数据共享!
docker run -it -v /home/docker_v:/home centos /bin/bash
docker inspect [容器id]
5.2,实战:mysql
docker pull mysql
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=你自己设置的数据库密码 --name mysql-wanyu mysql
# 下面的是官方测试
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
使用dbeaver直接连接mysql成功!注意需要修改其中的allowPublicKeyRetrieval=true配置!
直接在mysql中创建一个新的数据库时,由于容器数据卷技术本地目录会有test库相关文件变更
5.3,具名和匿名挂载
# 匿名挂载
-v 容器路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx # 匿名挂载(待测试)
docker run -d -P --name nginx02 -v nginx-wanyu:/etc/nginx nginx # 具名挂载
docker volume ls # 查看数据卷情况
# 这个可以发现volume name中会有相关的匿名挂载
查看匿名挂载的目录
docker inspect [容器id]
docker volume inspect nginx-wanyu
如何确定是具名挂载还是匿名挂载,还是指定路径挂载?
-v 容器路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载
拓展:
# 通过 -v 容器内路径:ro rw 改变读写权限
# ro readonly
# rw readwrite
docker run -d -P --name nginx03 -v nginx-wanyu:/etc/nginx:ro nginx
docker run -d -P --name nginx03 -v nginx-wanyu:/etc/nginx:rw nginx
5.4,打包样例centos(展示volume特性)
# 创建一个dockerfile文件,名字可以随机 建议Dockerflie
# 文件中的内容 指令(大写)
FROM centos
VOLUME ["/volume01","/volume02"]
CMD echo "----end-----"
CMD /bin/bash
# 里面每一个命令就是镜像的一层
docker build -f /home/docker-test-volume/dockerfile1 -t wanyu/centos:1.0 .
5.5,数据卷容器
多个centos同步数据
docker run -it --name docker01 wanyu/centos:1.0
docker run -it --name docker02 --volumes-from docker01 wanyu/centos:1.0
# 此时两个容器的自定义数据卷是共享的!(通过--volumes-from创建的容器,其数据是共享的)
docker01中的volume是匿名数据卷,删除docker01,其他的容器数据卷不受影响!
多个mysql实现数据共享(当前不好实现!)
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=activeclub --name mysql-wanyu01 mysql
docker run -d -P -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql
docker run -d -P -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 mysql
docker run -d -P --volumes-from mysql02 -e MYSQL_ROOT_PASSWORD=123456 --name mysql03 mysql
docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=activeclub --name mysql-wanyu0 mysql
docker run -d -p 3311:3306 --volumes-from mysql-wanyu0 -e MYSQL_ROOT_PASSWORD=activeclub --name mysql-wanyu1 mysql
报错
好像会因为这个数据卷已经被其他容器读写中,导致本次读写被拒绝了!
当前的情况是:只有关闭原有的mysql-wanyu0容器,才能正常使用mysql-wanyu1
6,DockerFile
DockerFile就是用来构建docker镜像的构建文件!命令脚本
通过这个脚本可以生成镜像,镜像是一层层的,脚本的一个个的命令
6.1,基础知识
构架步骤:
1,编写一个dockerfile文件
2,docker build构建成一个镜像
3,docker run 运行镜像
4,docker push 发布镜像(dockerHub、阿里云镜像仓库)
dockerfile是面向开发的,以后要发布项目,做镜像,需要编写dockerfile文件,这个文件十分简单!
docker镜像逐渐成为企业交付的标准,必须掌握!
dockerfile:构建文件,构建了一切的步骤,源代码(编译链)
docker image:通过dockerfile构建生成的镜像,最终发布和运行的产品,原来是jar、war,后续就是直接docker镜像部署
docker container:容器就是镜像运行起来提供服务的组件!
6.2,dockerfile命令
1,每个保留关键字(指令)都必须是大写
2,执行是从上到下
3,# 表示注释
4,每个指令都会创建提交一个新的镜像,并提交
FROM # 基础进行,一切从这里开始构建
MAINTAINER # 镜像的作者,姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤,添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的数据卷
EXPOSE # 暴露端口配置
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承的dockerfile,这个时候就会运行ONBUILD,触发指令
COPY # 类似ADD,将我们的文件拷贝到镜像中
ENV # 构建的时候设置环境变量,设置内存大小或者其他环境参数
6.3,实战:centos
docker hub中99%的镜像都是以FROM scratch开始!然后配置需要的软件和配置来构建的
任务:构建一个带有vim、ifconfig命令的centos镜像
# 1。编写dockerfile的文件dockerfile-centos
FROM centos
MAINTAINER wanyu<XXXXXX@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
# 2,通过dockerfile文件构建镜像
docker build -f dockerfile-centos -t wanyu-centos:1.0 .
点击查看docker stats
[root@iZbp1jbs6mikemed8a6mooZ:/home/dockerfile-test]# docker build -f dockerfile-centos -t wanyu-centos:1.0 . Sending build context to Docker daemon 2.048kB Step 1/10 : FROM centos ---> 5d0da3dc9764 Step 2/10 : MAINTAINER wanyu ---> Running in e6809c7dd314 Removing intermediate container e6809c7dd314 ---> 0ea1bdd2f8ec Step 3/10 : ENV MYPATH /usr/local ---> Running in 68267f5b4fe0 Removing intermediate container 68267f5b4fe0 ---> 62d54a07b103 Step 4/10 : WORKDIR $MYPATH ---> Running in cc5b572d010f Removing intermediate container cc5b572d010f ---> 1ea33fe2b5ef Step 5/10 : RUN yum -y install vim ---> Running in 538d3635db9a CentOS Linux 8 - AppStream 771 kB/s | 8.2 MB 00:10 CentOS Linux 8 - BaseOS 4.3 MB/s | 3.5 MB 00:00 CentOS Linux 8 - Extras 19 kB/s | 10 kB 00:00 Dependencies resolved. ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: vim-enhanced x86_64 2:8.0.1763-16.el8 appstream 1.4 M Installing dependencies: gpm-libs x86_64 1.20.7-17.el8 appstream 39 k vim-common x86_64 2:8.0.1763-16.el8 appstream 6.3 M vim-filesystem noarch 2:8.0.1763-16.el8 appstream 49 k which x86_64 2.21-16.el8 baseos 49 k Transaction Summary ================================================================================ Install 5 Packages Total download size: 7.8 M Installed size: 30 M Downloading Packages: (1/5): gpm-libs-1.20.7-17.el8.x86_64.rpm 231 kB/s | 39 kB 00:00 (2/5): vim-filesystem-8.0.1763-16.el8.noarch.rp 475 kB/s | 49 kB 00:00 (3/5): which-2.21-16.el8.x86_64.rpm 389 kB/s | 49 kB 00:00 (4/5): vim-enhanced-8.0.1763-16.el8.x86_64.rpm 652 kB/s | 1.4 MB 00:02 (5/5): vim-common-8.0.1763-16.el8.x86_64.rpm 527 kB/s | 6.3 MB 00:12 -------------------------------------------------------------------------------- Total 563 kB/s | 7.8 MB 00:14 warning: /var/cache/dnf/appstream-02e86d1c976ab532/packages/gpm-libs-1.20.7-17.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY CentOS Linux 8 - AppStream 1.6 MB/s | 1.6 kB 00:00 Importing GPG key 0x8483C65D: Userid : "CentOS (CentOS Official Signing Key) " Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D From : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial Key imported successfully Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Preparing : 1/1 Installing : which-2.21-16.el8.x86_64 1/5 Installing : vim-filesystem-2:8.0.1763-16.el8.noarch 2/5 Installing : vim-common-2:8.0.1763-16.el8.x86_64 3/5 Installing : gpm-libs-1.20.7-17.el8.x86_64 4/5 Running scriptlet: gpm-libs-1.20.7-17.el8.x86_64 4/5 Installing : vim-enhanced-2:8.0.1763-16.el8.x86_64 5/5 Running scriptlet: vim-enhanced-2:8.0.1763-16.el8.x86_64 5/5 Running scriptlet: vim-common-2:8.0.1763-16.el8.x86_64 5/5 Verifying : gpm-libs-1.20.7-17.el8.x86_64 1/5 Verifying : vim-common-2:8.0.1763-16.el8.x86_64 2/5 Verifying : vim-enhanced-2:8.0.1763-16.el8.x86_64 3/5 Verifying : vim-filesystem-2:8.0.1763-16.el8.noarch 4/5 Verifying : which-2.21-16.el8.x86_64 5/5 Installed: gpm-libs-1.20.7-17.el8.x86_64 vim-common-2:8.0.1763-16.el8.x86_64 vim-enhanced-2:8.0.1763-16.el8.x86_64 vim-filesystem-2:8.0.1763-16.el8.noarch which-2.21-16.el8.x86_64 Complete! Removing intermediate container 538d3635db9a ---> 6e05fa365556 Step 6/10 : RUN yum -y install net-tools ---> Running in 37e396baef2f Last metadata expiration check: 0:00:23 ago on Sun Dec 5 15:38:25 2021. Dependencies resolved. ================================================================================ Package Architecture Version Repository Size ================================================================================ Installing: net-tools x86_64 2.0-0.52.20160912git.el8 baseos 322 k Transaction Summary ================================================================================ Install 1 Package Total download size: 322 k Installed size: 942 k Downloading Packages: net-tools-2.0-0.52.20160912git.el8.x86_64.rpm 1.5 MB/s | 322 kB 00:00 -------------------------------------------------------------------------------- Total 470 kB/s | 322 kB 00:00 Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Preparing : 1/1 Installing : net-tools-2.0-0.52.20160912git.el8.x86_64 1/1 Running scriptlet: net-tools-2.0-0.52.20160912git.el8.x86_64 1/1 Verifying : net-tools-2.0-0.52.20160912git.el8.x86_64 1/1 Installed: net-tools-2.0-0.52.20160912git.el8.x86_64 Complete! Removing intermediate container 37e396baef2f ---> 6bda7a481d68 Step 7/10 : EXPOSE 80 ---> Running in 6d975d602b27 Removing intermediate container 6d975d602b27 ---> d79a352bafc1 Step 8/10 : CMD echo $MYPATH ---> Running in 1e98f38f7472 Removing intermediate container 1e98f38f7472 ---> 25aa4791b8c4 Step 9/10 : CMD echo "----end----" ---> Running in ab3d6b669573 Removing intermediate container ab3d6b669573 ---> 7a046095a7b7 Step 10/10 : CMD /bin/bash ---> Running in 1f30a110730a Removing intermediate container 1f30a110730a ---> 16fb3dd27c56 Successfully built 16fb3dd27c56 Successfully tagged wanyu-centos:1.0
可以通过docker history [镜像id]查看镜像构建历史
例如:postgres的构建历史
CMD与ENTRYPOINT区别(待实践)
测试CMD命令
测试ENTRYPOINT命令
# 直接执行docker run id -l
很多命令只有细微的区别,最好的学习就是对比执行效果!
6.4,实战:Tomcat镜像
两个关键的文件下载地址
https://mufasa-blog-images.oss-cn-beijing.aliyuncs.com/img/apache-tomcat-9.0.33.tar.gz
https://mufasa-blog-images.oss-cn-beijing.aliyuncs.com/img/jdk-8u311-linux-x64.tar.gz
FROM centos
MAINTAINER wanyu<xxxx@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u311-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.33.tar.gz /usr/local
RUN yum -y install vim
ENV MYPATH /usr/local/jdk1.8.0_311
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_311
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.33
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD touch /usr/local/apache-tomcat-9.0.33/logs/catalina.out
CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.33/logs/catalina.out
docker build -t wanyuTomcat .
docker run -d -p 9090:8080 --name wanyuTomcat 1f4f43c5147a
6.5,发布镜像到阿里云
1,直接登录阿里云,进入控制台搜索镜像服务
2,自己创建镜像仓库
3,直接在镜像仓库中有类似github仓库的命令教学
docker login --username=XXXXX registry.cn-hangzhou.aliyuncs.com # 登录镜像
docker pull registry.cn-hangzhou.aliyuncs.com/activeclub/private:[镜像版本号]
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/activeclub/private:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/activeclub/private:[镜像版本号]
6.6,将自己的springBoot项目打包docker镜像(待)
使用阿里云流水线CI/CD持续化集成工具很方便(devops)
1,构架springboot项目
2,打包应用
3,编写dockerfile
4,构架镜像
5,发布运行
流程:
1,
7,Docker网络
ip addr
# lo:本机回环地址
# eth0:阿里云内网地址
# docker0:docker生成的地址
# 代表三种不同的环境,docker如何处理网络访问?
veth-path虚拟网络技术
docker中的所有网络接口都是虚拟的,虚拟的转发效率高!
高可用问题:
docker中直接使用类似consul那种服务名注册的形式,以容器名称来代替ip,实现重启动态更换ip但是不用额外更换ip
7.2,--link
docker run -d -P --name tomcat02 --link tomcat01 tomcat
# 之后就可以直接在tomcat02容器中直接
ping tomcat01
7.3,自定义网络
docker network ls
网络模式:
bridge:桥接docker(默认,自定义)
none:不配置网络
host:和宿主机共享网络
container:容器网络联调(使用较少,局限较大)
# 启动命令 --net bridge,这个就是docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点:默认,域名不能访问,--link可以打通连接
# 可以自定义网络
# --dirver bridge
# --subnet 192.168.0.0/16
# --gateway 192.168.0.1
docker network create --driver bridge --subnet 192.168.0.0/16 --getway 192.168.0.1 mynet
直接将容器运行在自定义的网络中,同一个网路中的容器之间可以通过名字互相ping通网络!!!
优势:不同的集群使用不同的网络,保证集群网络是安全和健康的
7.4,网络联通
# 测试打通tomcat - mynet
docker network connect mynet tomcat03
# 联通之后就是tomcat01放到mynet网络下
# 一个容器两个ip
# 阿里云服务:公网ip、私网ip
7.5,部署redis集群(待)
8,参考链接
1,https://docs.docker.com/get-started/overview/
8,jenkins