type
Post
status
Published
date
Jul 28, 2022
slug
article-11
summary
Docker 容器服务系统 全精通
tags
容器操作
运维
docker
category
技术分享
icon
password
Property
Jul 28, 2022 10:14 AM
仓库地址
实战演示地址:
docker 的常用命令
帮助命令
docker version # 显示docker的版本信息 docker info # docker详细信息 docker 命令 --help # 万能命令
镜像命令
docker images 查看所有本地主机上的镜像
[root@mushan /] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d1165f221234 5 months ago 13.3kB # 解释 REPOSITORY 镜像仓库源 TAG 镜像的标签 IMAGE ID 镜像的ID CREATED 镜像创建的时间 SIZE 镜像的大小 # 可选项(可混合使用) -a, --all 列出所有镜像 -q, --quiet 只显示镜像的id
docker search 搜索镜像
➜ mushan docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation… 11308 [OK] mariadb MariaDB Server is a high performing open sou… 4294 [OK] mysql/mysql-server Optimized MySQL Server Docker images. Create… 838 [OK] # 解释 NAME 镜像仓库源的名称 DESCRIPTION 镜像描述 START 点赞量 OFFICIAL 是否 docker 官方发布 AUTOMATED 自动构建 # 可选项, 通过搜索来过滤 --filter=STARS=3000 # 搜索镜像STARS大于3000
docker pull 下载镜像
# 下载镜像 docker pull 镜像名[:tag](版本默认为最新) [root@mushan /]# docker pull mysql Using default tag: latest # 如果不写tag, 默认为latest(最后一个, 最新版) latest: Pulling from library/mysql e1acddbe380c: Pull complete # 分层下载, docker image的核心 联合文件系统 bed879327370: Pull complete 03285f80bafd: Pull complete ccc17412a00a: Pull complete 1f556ecc09d1: Pull complete adc5528e468d: Pull complete 1afc286d5d53: Pull complete 6c724a59adff: Pull complete 0f2345f8b0a3: Pull complete c8461a25b23b: Pull complete 3adb49279bed: Pull complete 77f22cd6c363: Pull complete Digest: sha256:d45561a65aba6edac77be36e0a53f0c1fba67b951cb728348522b671ad63f926 # 签名(防伪) Status: Downloaded newer image for mysql:latest docker.io/library/mysql:latest # 真实地址 # 等价于 docker pull mysql docker pull docker.io/library/mysql:latest # 下载特定版本 [root@mushan /]# docker pull mysql:5.7 5.7: Pulling from library/mysql # tag == 5.7 e1acddbe380c: Already exists # 前面已经安装了mysql最新版, 5.7版本有重复内容, 共用无需下载 bed879327370: Already exists 03285f80bafd: Already exists ccc17412a00a: Already exists 1f556ecc09d1: Already exists adc5528e468d: Already exists 1afc286d5d53: Already exists 4d2d9261e3ad: Pull complete ac609d7b31f8: Pull complete 53ee1339bc3a: Pull complete b0c0a831a707: Pull complete Digest: sha256:7cf2e7d7ff876f93c8601406a5aa17484e6623875e64e7acc71432ad8e0a3d7e Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7 #查看本地镜像 ➜ / docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql 5.7 6c20ffa54f86 4 days ago 448MB mysql latest 5a4e492065c7 4 days ago 514MB hello-world latest d1165f221234 5 months ago 13.3kB # 此时同时存在 mysql:latset 和 mysql:5.7 两个版本
docker rmi 删除镜像
# 通过ID删除 docker rmi -f ID #删除指定容器 docker rmi -f ID ID ID #删除多个指定容器 docker rmi -f $(docker images -aq) #删除全部容器
➜ mushan docker rmi -f 6c20ffa54f86 Untagged: mysql:5.7 Untagged: mysql@sha256:7cf2e7d7ff876f93c8601406a5aa17484e6623875e64e7acc71432ad8e0a3d7e Deleted: sha256:6c20ffa54f8674203e91e3225e489aa505fa04b8d482954a8b6d7414842c6de4 Deleted: sha256:7ecf077dd9d6725f0e594b9cd5eb214ad1b3764fa75bf5940ab08b05b8bae184 Deleted: sha256:c28edab85681de37f9d2a75dde941a20d2e1ac6e4efb7dee391913d3ec722fef Deleted: sha256:6c11b187da1ecb65ce10b25f54354f3515ce9d26fabcd859cdb43dbd625df907 Deleted: sha256:d0dfc5be0883ed4af9f642a8e4f2312a93c4241ec8e89f22219b0f0a0d26c8d3 # 只删除与 mysql:latest 不共用的内容 # 删除本地全部docker镜像 ➜ mushan docker rmi -f $(docker images -aq) $: 表示把括号里面的内容作为参数传入 docker images -aq: 表示查出本地所有的镜像ID ➜ mushan docker images # 此时镜像列表为空 REPOSITORY TAG IMAGE ID CREATED SIZE
# 通过命名删除 docker rmi -f 镜像名[:tag] # 删除指定容器单个版本 docker rmi -f $(docker images mysql -aq) # 删除指定容器全部版本 docker rmi -f 镜像名[:tag] 镜像名[:tag] # 删除多个指定容器单个版本 ... 同等嵌套类似
inspect 查看镜像数据源
docker inspect 容器ID
容器命令
说明: 有了镜像之后才可以创建容器, linux, 下载一个centos镜像测试学习
docker pull centos
新建容器并启动
docker run[可选参数] image # 参数说明 --name="Name" 容器名字 name1 name2, 用来区分容器 -d 以后台方式运行 -it 使用交互方式运行, 进入容器查看内容 -i 允许你对容器内的标准输入 (STDIN) 进行交互。 -t 在新容器内指定一个伪终端或终端。 -p(小写) 指定容器的端口 -p 8080:8080 -P(大写) 随机指定端口
#-p(小写) 格式: -p 主机端口:容器端口 #(常用) -p 容器端口 容器端口
!测试 # 启动并进入容器 ➜ / docker run -it centos /bin/bash [root@9e8f5d24331a /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var # 从容器中退回主机 exit ➜ / ls bin boot dev etc home lib lib64 lost+found mnt opt proc root run sbin srv sys tmp usr var
列出运行的容器
docker ps 列出当前正在运行的容器完整信息 docker ps -a 列出历史运行过的容器完整信息 docker ps -n=? 列出?个历史运行过的容器完整信息 docker ps -q 列出当前正在运行的容器编号 #[可选项]可以混合使用
# 测试 ➜ / docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9b8c37b20ae6 centos "/bin/bash" 35 minutes ago Up 22 minutes vigilant_thompson # 输出详情介绍 CONTAINER ID: 容器 ID。 IMAGE: 使用的镜像。 COMMAND: 启动容器时运行的命令。 CREATED: 容器的创建时间。 STATUS: 容器状态。 PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。 NAMES: 自动分配的容器名称。 # 7种状态 created (已创建) restarting (重启中) running / Up (运行中) removing (迁移中) paused (暂停) exited (停止) dead (死亡)
退出容器
exit # 直接容器停止并退出 ctrl + p + q # 退出, 但不停止容器
启动和停止容器操作
docker start 容器id # 启动容器 docker restart 容器id # 重启容器 docker stop 容器id # 停止当前正在运行的容器 docker kill 容器id # 强制停止当前正在运行容器
导出和导入容器快照
导出容器快照: docker export 容器id > 文件名 docker export 1e560fca3906 > centos.tar 导出容器快照: cat docker /文件名 | docker import - test/镜像名:[:tag] cat docker/centos.tar | docker import - test/ubuntu:v1 #此外,也可以通过指定 URL 或者某个目录来导入,例如: docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器
docker rm 容器ID # 删除指定容器 docker rm -f $(docker ps -aq) # 删除全部容器(-f 表强制 可删除正在运行容器) docker ps -a -q|xargs docker rm # 删除全部容器
常用其他命令
后台启动容器:
# 通过-d 方式创建容器 docker run -d 镜像名 docker run -d centos # 问题docker ps. 发现 centos 停止了 # 常见的坑, docker 容器使用后台运行, 就必须要有一个前台进程, 如果没有前台进程, 只在后台运行, docker发现没有应用, 就会自动停止nginx, 容器启动后, 发现自己没有提供服务, 就会立刻停止(自杀), 就是没有程序了 一般采用 -itd 来后台启动
查看日志
docker logs -f -t --since="时间戳" --tail=查看个数 容器id # 例: docker logs -f -t --since="2019-04-15T02:14:00" --tail=1000 9c03ea2c # 参数解释 -f: 动态实时显示 -t: 显示日志生成时的时间戳 --since: 从指定时间戳开始(默认中时区,即在北京东八区的时间戳上减去8小时) --tail / -n: 显示最后的条数 # 测试: # 自己编写一端shell脚本 docker run -d centos /bin/bash -c "while true; do echo mushan;sleep 1;done"
查看容器中进程信息
# top命令 ➜ / docker top 5ba11c251c85 UID PID PPID C STIME TTY TIME root 23430 23399 0 16:27 ? 00:00:00 root 27032 23430 0 16:52 ? 00:00:00 # 解释 UID 用户ID PID 进程ID PPID 父进程ID
查看镜像源数据
# inspect命令 docker inspect 容器ID
[ { "Id": "5ba11c251c8508d2519c67e708fce5a8e2ccbbd753cc89245554bae37f5b82d7", "Created": "2021-08-22T16:27:38.5583555Z", "Path": "/bin/bash", "Args": [ "-c", "while true; do echo mushan;sleep 1;done" ], "State": { "Status": "running", "Running": true, "Paused": false, ... ... ... ... ... . } ... ... ... ... ... ... ]
进入当前正在运行的容器
# 容器通常使用后台方式运行, 有时需要进入容器, 修改一些配置 # 方式一: (进入容器后开启一个新的终端, 可以在里面操作) #docker exec -it 容器id bashShell ➜ / docker exec -it 5ba11c251c85 /bin/bash # 方式二: #docker attach 容器id (进入容器正在执行的终端, 不会启动新的进程!) ➜ / docker attach 5ba11c251c85 正在执行当前的代码...
从容器内拷贝文件到主机
docker cp 容器id:容器内路径 目的主机路径 容器id 使用 docker ps -a查看(即是容器关闭了, 只要容器还在, 就可以获取内容) 转到主机 # 测试: docker cp 872613da391c:/home/mushan.cpp /home ➜ /home ls docker_ceshi.txt mushan mushan.cpp(这个就是拷贝过来的内容)
可视化
- portainer
- Rancher ( CI/CD 再用)
portainer
什么是 portainer ?
Docker图形化界面管理工具 ! 提供一个后台面板操作 !
安装运行:
➜ / docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
Unable to find image 'portainer/portainer:latest' locally Blatest: Pulling from portainer/portainer 94cfa856b2b1: Pull complete 49d59ee0881a: Pull complete a2300fd28637: Pull complete Digest: sha256:fb45b43738646048a0a0cc74fcee2865b69efde857e710126084ee5de9be0f3f Status: Downloaded newer image for portainer/portainer:latest 7502fee2a1282c2302530f18b07ec2f52540eb3407cd2d21a07b0702111250f9
访问测试 : 外网 : 8088
浏览器查看: http://localhost:8088/

访问成功!
Username: admin Password: 12345678
进入本地仓库

Commit镜像
格式
docker commit 提交容器成为一个新的副本 # 命令和git原理类似 docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
实战测试
# 启动一个默认的tomcat # 官方的镜像中, webapps 中默认是没有文件的 # webapps.dist 中 拷贝内容给 webapps. # 此时我在容器里面在官方tomcat的基础上发了改变 # 我认为我修改后的容器更加方便, 想把它打包成容器.
➜ ~ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b09303c24d37 tomcat "catalina.sh run" 14 minutes ago Up 14 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp funny_einstein ➜ ~ docker commit -a="mushan" -m="add webapps app cp webapps.dist" b09303c24d37 tomcat_mushan:1 .0 sha256:c24575315327b17d7abd6d8f9904f4721e10098f9b6efda0903855531d0961d1 ➜ ~ docker images REPOSITORY TAG IMAGE ID CREATED SIZE tomcat_mushan 1.0 c24575315327 8 seconds ago 673MB tomcat latest 266d1269bb29 6 days ago 668MB nginx latest dd34e67e3371 8 days ago 133MB portainer/portainer latest 580c0e4e98b0 5 months ago 79.1MB centos latest 300e315adb2f 8 months ago 209MB kibana 7.6.2 f70986bc5191 17 months ago 1.01GB elasticsearch 7.6.2 f29a1ee41030 17 months ago 791MB ➜ ~ # 这里出现了我们打包提交成功的 tomcat_mushan
对比 tomcat 和 tomcat_mushan
# tomcat_mushan (共11层) ... ... ... ...省略 "RootFS": "sha256:c2ddc1bc2645ab5d982c60434d8bbc6aecee1bd4e8eee0df7fd08c96df2d58bb", "sha256:62d14713f2e98841ec3927e3ab611b13e414a21fb82fc0e604a9008ac53e45dc", "sha256:1235daf38153d083ae5b4f605acc54f9401143b5fbd033801ba373a8cfb04845", "sha256:7d890913ab6955350bdd25d04c60dd444db13890c401cbcdc8e00e9bd29c90fc", "sha256:c2e2307780ac2fa0d39cec874c4545156da890c1bcc42b3259114ac29bb598f1", "sha256:75f6a0e6e441cd3d74125443fc73eb26bf9ceb557b269b25bddaa2ef459227f7", "sha256:b19f17003e5ae07f7aba99f95736627aaa1ff3c92832f7d6920158dc6b138bcf", "sha256:2dad09b8a57e12408adc0366cbd2a642eaab1c82bbfb2b442245928b60d337f1", "sha256:83a14c3e974e700768197a3061f840618a924d3154fcb338a85b6da5fd4eb886", "sha256:19f8bd134bcf7c5870f8294b1d3bba4c970d0b622772865e44d200d248ed2676", "sha256:997ad98329327bc8cc90838a8804a5ad4c93d5286e03decf2715bbb035e4a5a1" ... ... ... ...省略 # tomcat (共10层) ... ... ... ...省略 "RootFS": "sha256:c2ddc1bc2645ab5d982c60434d8bbc6aecee1bd4e8eee0df7fd08c96df2d58bb", "sha256:62d14713f2e98841ec3927e3ab611b13e414a21fb82fc0e604a9008ac53e45dc", "sha256:1235daf38153d083ae5b4f605acc54f9401143b5fbd033801ba373a8cfb04845", "sha256:7d890913ab6955350bdd25d04c60dd444db13890c401cbcdc8e00e9bd29c90fc", "sha256:c2e2307780ac2fa0d39cec874c4545156da890c1bcc42b3259114ac29bb598f1", "sha256:75f6a0e6e441cd3d74125443fc73eb26bf9ceb557b269b25bddaa2ef459227f7", "sha256:b19f17003e5ae07f7aba99f95736627aaa1ff3c92832f7d6920158dc6b138bcf", "sha256:2dad09b8a57e12408adc0366cbd2a642eaab1c82bbfb2b442245928b60d337f1", "sha256:83a14c3e974e700768197a3061f840618a924d3154fcb338a85b6da5fd4eb886", "sha256:19f8bd134bcf7c5870f8294b1d3bba4c970d0b622772865e44d200d248ed2676" ... ... ... ...省略 # 可以发现 tomcat 和 tomcat_mushan 仅仅在tomcat的基础上多加了最后一层
启动 tomcat_mushan 试试效果:
➜ ~ docker run -it -p 8081:8081 tomcat_mushan:1.0
tomcat_mushan:

tomcat:

容器数据卷
什么是容器数据卷
docker的理念回顾
例: 将一个MySQL容器打包成一个镜像 !
当删除这个这个容器的时候, 里面存储的数据文件就会丢失 ! (删库跑路)
此时这种情况会很危险
需求: 数据持久化
需求:MySQL数据可以存储在本地 !
为了实现这一需求, 容器之间可以由一个数据共享技术 (卷技术) ! Docker 容器中产生的数据, 同步到本地
如何使用卷 : -v 挂载
docker run -it -v 主系统的一个路径:容器中的一个路径 # centos容器为例 docker run -it -v /home/ceshi:/home centos /bin/bash # 此时 主文件系统和容器文件系统 挂载的路径将会互通 无论容器是否处于运行状态, 无论是哪一路径下内容发生改变, 另一方都会同时发生相同的变化 容器和主系统两端一直是一致互通的
具名和匿名挂载
-v 容器内路径 docker run -d -P --name nginx01 -v /etc/nginx nginx (匿名) # 匿名挂载: 只写容器内路径, 不写容器外路径 docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx (具名) # 具名挂载: 通过 -v 卷名:容器内路径
volume 卷命令
docker volume --help Commands: create Create a volume inspect Display detailed information on one or more volumes ls List volumes prune Remove all unused local volumes rm Remove one or more volumes
➜ / docker volume ls DRIVER VOLUME NAME local 4b13ad4d9594573dc7d7b2cc944ae56b838c3b437aa3735377fb0f25c25cb526 local d205865d4dcd5d50c97c09f532d580350f65180f2d1b3f48b425a71ea9ed0135 local juming-nginx # 前两个分别是mysql 和 nginx 的匿名挂载, 第三个是 nginx 的具名挂载
➜ / docker volume inspect juming-nginx [ { "CreatedAt": "2021-08-27T07:27:06Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", "Name": "juming-nginx", "Options": null, "Scope": "local" } ]
➜ / docker volume inspect d205865d4dcd5d50c97c09f532d580350f65180f2d1b3f48b425a71ea9ed0135 [ { "CreatedAt": "2021-08-27T06:49:28Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/d205865d4dcd5d50c97c09f532d580350f65180f2d1b3f48b425a71ea9ed0135/_data", "Name": "d205865d4dcd5d50c97c09f532d580350f65180f2d1b3f48b425a71ea9ed0135", "Options": null, "Scope": "local" } ]
所有没设定挂载路径的卷, 默认都在路径
/var/lib/docker/volumes/挂载名/_data_ 路径下挂载名, 如果是具名挂载就是以-v后的子串命名, 否则为匿名挂载以生成的一段规律字串命名
通过 -v 容器内路径: ro / rw 改变读写权限
# 通过 -v 容器内路径: ro / rw 改变读写权限(默认是rw) ro: readonly #只读 rw: readwrite #读写 docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:ro nginx docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx # 一旦设置了容器权限, 容器对挂载出来的内容就有了限定 # 设定为 ro 时, 这个路径将只能通过宿主机来操作, 容器内部是无法操作的
初始Dockerfile
Dockerfile: 用来构建 docker 镜像的构建文件 ! 命令脚本 !
通过这个脚本可以生成镜像, 镜像是一层一层的, 脚本一个个的命令, 每个命令都是一层
创建路径 mkdir /home/docker-test-volume 创建编辑文件 vim dockerfile1
# 自定义Dockerfile FORM centos # 以centos为基础 VOLUME ["volume01", "volume02"] # 挂载目录(这里是匿名挂载) CMD echo "----end----" # 完成后输出"----end----" CMD /bin/bash # 默认进入使用 bash 控制台
➜ / docker build -f /home/docker-test-volume/dockerfile1 -t mushan/centos:1.0 . # 参数说明 build 命令构建镜像 -f 通过什么脚本文件构建(脚本路径) -t 生成: 镜像名:[tag] . 当前目录 # 返回内容: Sending build context to Docker daemon 2.048kB Step 1/4 : FROM centos ---> 300e315adb2f Step 2/4 : VOLUME ["volume01", "volume02"] ---> Running in add71936df4a Removing intermediate container add71936df4a ---> f005f45db9de Step 3/4 : CMD echo "----end----" ---> Running in 01b8f543c1bc Removing intermediate container 01b8f543c1bc ---> 0ef638078484 Step 4/4 : CMD /bin/bash ---> Running in 89be86ba72c5 Removing intermediate container 89be86ba72c5 ---> 37a96d02edb1 Successfully built 37a96d02edb1 Successfully tagged mushan/centos:1.0 # 成功生成镜像 ➜ docker-test-volume docker images REPOSITORY TAG IMAGE ID CREATED SIZE mushan/centos 1.0 37a96d02edb1 6 minutes ago 209MB
数据卷容器
通过
--volumes-from命令, 实现两个容器之间的挂载与数据同步 (伪同步)测试:
创建三个centos镜像
docker run -it --name="centos01" mushan/centos:1.0 /bin/bash docker run -it --name="centos02" --volumes-from centos01 centos:latest /bin/bash docker run -it --name="centos03" --volumes-from centos01 centos:latest /bin/bash # 规则1: 必须有一个容器与宿主机某路径同步挂载 # 规则2: 仅仅同步与宿主机挂载的路径 --volumes-from 命令只不过是把centos01 与宿主机挂载的内容cp了进去 # 三个容器同时同步宿主机挂载路径 同步成功后...
# 进入宿主机挂载路径, 发现内容是同步的 ➜ _data pwd /var/lib/docker/volumes/4883e91e3f0583ba8e03081644542386ef685b28bd34bcb9c1e86fb3566dec7c/_data ➜ _data ls mushan # 把路径删除/4883e91e3f0583ba8e03081644542386ef685b28bd34bcb9c1e86fb3566dec7c rm -rf 4883e91e3f0583ba8e03081644542386ef685b28bd34bcb9c1e86fb3566dec7c # 此时无论在哪个容器中创建文件/文件夹都会失败 [root@6dd479046fcf volume01]# mkdir mushan mkdir: cannot create directory 'mushan': No such file or directory # 此时就算把文件夹创建回来也没有用
DockerFile
Dockerfile: 用来构建 docker 镜像的构建文件 ! 命令脚本 !
构建步骤
- 编写一个dockerfile文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像( Docker Hub , 阿里云镜像仓库)
# centos-8官方dockerfile FROM scratch ADD centos-8-x86_64.tar.xz / LABEL \ org.label-schema.schema-version="1.0"\ org.label-schema.name="CentOS Base Image"\ org.label-schema.vendor="CentOS"\ org.label-schema.license="GPLv2"\ org.label-schema.build-date="20201204" CMD ["/bin/bash"]
DockerFile 的创建
FROM # 指定基础镜像, 一切从这里开始构建 MAINTAINER # 指定维护者信息(姓名 + 邮箱) RUN # 运行一些内容, 可以echo输出一些东西 COPY # 将文件拷贝到镜像中 ADD # COPY文件, 会自动解压 WORKDIR # 设置默认工作目录 VOLUME # 设置卷, 挂载主机目录 EXPOSE # 暴露端口 CMD # 指定容器启动时要运行的命令(只有最后一个会生效, 会被覆盖) ENTRYPOINT # 指定容器启动时要运行的命令, 可追加命令 ONBUILD # 被继承时触发指令 ENV # 创建时设置环境变量 CMD: 命令可以用于默认设置, 比如启动方式/bin/bash为默认, 但是如果用户想通过其他的方式启动, 默认失效
发布镜像
DockerHub
- 登录DockerHub
docker login 用户名 password: 输入密码
- tag命令修改镜像名(添加一个标签)
docker tag 本地镜像名[:tag] 要修改的镜像名[:tag] # 一般使用 mushan/镜像名 命名
- 上传镜像
docker push 修改后的镜像名[:tag]
- Author:mushan
- URL:https://blog.mushan.xyz/article/article-11
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts

