2021年1月

https://docs.docker.com/swarm/overview/

2015 年年初,libswarm 项目开发六个月之后,Docker 向公众发布了 Swarm 的第一个 Beata 版本。Swarm 的目的是为 docker 客户端工具提供统一的接口,让它不仅能管理单个 Docker 守护进程,还能管理整个集群。Swarm 不是配置应用或实现可重复部署的工具,其作用是为 Docker 现有的工具提供集群资源管理能力。

架构

2022-10-04T12:54:02.png

进阶

Swarm集群(2manager-3worker)

https://docs.docker.com/engine/swarm/ swarm入门操作

In Docker 1.12 and higher;Swarm已经内置了,无需安装

8容器-->1个服务。 redis有8个实例。

对象-->类。

raft:大多,manager节点存活。worker不参与集群一致性。

2-manager >1台;生产环境最少3 manager;炸一个集群完美工作。

在所有docker主机上,选定一个主节点。运行docker swarm init --advertise-addr ip地址,初始化一个manager

docker swarm init \
--advertise-addr 192.168.121.142
--listen-addr 192.168.121.142
#关于advertise-addr和listen-addr这两个参数,前者用来指定其他节点连接m0时的地址,后者指定承载swarm流量的IP和端口

以后告别docker run

#1、docker-compose up 使用compose启动一个服务。docker-compose是单机下的玩具
#2、集群:docker service (使用docker管理服务。)容器升级为服务。
# docker service:管理集群里面的所有服务
# docker stack:管理集群的app stack;一个完整的应用有超多服务,就是一个服务栈

#扩容;
docker service create --name hello-nginx -p 8888:80 --replicas 3 nginx
docker service update --replicas 3 hello-nginx

#升级。滚动升级
docker service rollback hello-nginx; 当前+之前 来回回滚

#灰度发布,迭代。
docker service update --image nginx:1.18.0-alpine --update-parallelism 1 --update-delay 10s hello-nginx

docker service create 
#为什么每一个机器8888都能访问。

2022-10-04T12:58:32.png

剩下节点使用docker swarm join即可;

在主节点

docker swarm join-token manager
#可以生成Manager节点的join信息,再选中一个节点,运行命令就可以作为manager加入

docker node ls #查看节点信息

基本概念

1.Swarm
集群的管理和编排是使用嵌入docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm
2.Node
一个节点是docker引擎集群的一个实例。您还可以将其视为Docker节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。
要将应用程序部署到swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。
Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Manager节点选择单个领导者来执行编排任务。
工作节点接收并执行从管理器节点分派的任务。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。
3.Service
一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。
4.Task
任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点
------------------------------------------使用方法-------------------------------------
docker swarm:集群管理,子命令有init, ``join``, leave, update。(docker swarm --help查看帮助)
docker service:服务创建,子命令有create, inspect, update, remove, tasks。(docker service--help查看帮助)
docker node:节点管理,子命令有accept, promote, demote, inspect, update, tasks, ``ls``, ``rm``。(docker node --help查看帮助)

2022-10-04T12:55:39.png

Swarm的工作模式

Node

2022-10-04T12:59:32.png

Service

2022-10-04T13:00:22.png

3.任务与调度

2022-10-04T13:00:56.png

4.服务副本与全局服务

2022-10-04T13:00:38.png

3、测试

在Swarm中部署服务(nginx为例)

#1、可以创建网络
# docker network create -d overlay nginx_net
#2、部署service
docker service create --replicas 1 --name my_nginx -p 88:80 nginx    
# 就创建了一个具有一个副本(--replicas 1 )的nginx服务,使用镜像nginx
docker service ls
docker service inspect --pretty my_nginx
docker service ps my_nginx
#3、扩容
docker service scale my_nginx=4
docker service ps my_nginx
#4、模拟宕机查看效果
systemctl stop docker
docker node ls
docker service ps my_nginx
#5、Swarm 动态缩容服务(scale)
docker service scale my_nginx=1
#6、update扩缩容
docker service update --replicas 3 my_nginx
#7、update镜像升级
docker service update --image nginx:latest my_nginx
#8、服务移除
docker service rm my_nginx
#1、创建名为tomcat-net的覆盖网络(Overlay Netowork),这是个二层网络,处于该网络下的docker容器,即使宿主机不一样,也能相互访问:
docker network create -d overlay tomcat-net
#2、创建名为tomcat的服务,使用了刚才创建的覆盖网络:
docker service create --name tomcat \
--network tomcat-net \
-p 8080:8080 \
--replicas 2 \
tomcat:7.0.96-jdk8-openjdk
#3、执行命令docker service ls查看当前所有服务:
#4、执行命令docker service ps tomcat查看名为tomcat的服务,可见三个容器分别部署在m0、m2、w1机器上:
#5、执行命令docker service inspect --pretty tomcat查看名为tomcat的服务的详细信息(去掉--pretty可以看到更完整的):
#6、访问三个节点的tomcat,都能访问
#7、扩缩容
docker service scale tomcat=5
#8、滚动更新
docker service update \
--image tomcat:9.0.24-jdk11-openjdk \
--update-parallelism 1 \
--update-delay 10s tomcat
#update-parallelism:每次更新的容器数量,这里设置为1,表示每一个容器升级成功后才去升级下一个;
#update-delay:每一批升级成功后,升级下一批之前的等待时间,这里表示升级一个容器后等10秒再升级下一个;
#在升级过程中执行命令docker service ps tomcat查看服务,可以看到新版本容器逐个启动的过程:
#9、移除服务
docker service rm tomcat

服务模式

  • 服务模式一共有两种:Ingress和Host,如果不指定,则默认的是Ingress;

    • Ingress模式下,到达Swarm任何节点的8080端口的流量,都会映射到任何服务副本的内部80端口,就算该节点上没有tomcat服务副本也会映射;
    • Host模式下,仅在运行有容器副本的机器上开放端口,使用Host模式的命令如下:
docker service create --name tomcat \
--network tomcat-net \
--publish published=8080,target=8080,mode=host \
--replicas 3 \
tomcat:7.0.96-jdk8-openjdk

默认swarm集群的所有部署,(3副本)。

manager节点负责调度,真正会在其他节点执行(创建副本)【默认worker优先,基本随机】。我们不知道我们的容器最终会发配给那个服务器。指定服务器,给他部署上去(label)。

1、ssd硬盘 ,数据存储,mysql。合适作为数据节点,存储节点

2、cpu厉害,适合作为计算,大数据,数据分析框架,就应该优先调度到cpu厉害的。hadoop存储之类的,就应该调度到ssd磁盘。

Drain a node:排空节点。把节点里面的容器驱逐出去。
In earlier steps of the tutorial, all the nodes have been running with ACTIVE availability. The swarm manager can assign tasks to any ACTIVE node, so up to now all nodes have been available to receive tasks. ACTIVE的节点,manager就可以分配任务进行部署。

docker node update --availability drain worker1
#这台机器用service部署产生的所有容器,都被驱逐出去了。当前docker就没有service的容器。但是集群为了保证副本数量会在其他机器拉起。

docker node update --availability pause worker1 #暂停接受给我的任务。
 --availability active
#100 最好的状态,20台计算型的 。40台存储型的。30台冗余备份的
docker service hadoop --->调度到 40台存储型的;Label选择


# routing mesh;路由网
docker service create --name nginx -p 8080:80 --replicas 3 nginx
只要service是暴露端口的方式,全服务器都能访问。
#真正的nginx容器的ip
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:00:12 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.18/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
34: eth1@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever

#集群状态下,每个主机都会多两个网络
43c75b51441f        docker_gwbridge     bridge              local
o7b9pfkdt2ti        ingress             overlay             swarm

ingress: "Subnet": "10.0.0.0/24", "Gateway": "10.0.0.1"
docker_gwbridge:"Subnet": "172.18.0.0/16"
集群状态下,service创建的容器默认加入两个网络。 docker_gwbridge 、 ingress

4、Docker Stack和Docker Compose区别

  • Docker stack会忽略了“构建”指令,无法使用stack命令构建新镜像,它是需要镜像是预先已经构建好的。 所以docker-compose更适合于开发场景;
  • Docker Compose是一个Python项目,在内部,它使用Docker API规范来操作容器。所以需要安装Docker -compose,以便与Docker一起在您的计算机上使用;
  • Docker Stack功能包含在Docker引擎中。你不需要安装额外的包来使用它,docker stacks 只是swarm mode的一部分。
  • Docker stack不支持基于第2版写的docker-compose.yml ,也就是version版本至少为3。然而Docker Compose对版本为2和3的 文件仍然可以处理;
  • docker stack把docker compose的所有工作都做完了,因此docker stack将占主导地位。同时,对于大多数用户来说,切换到使用docker stack既不困难,也不需要太多的开销。如果您是Docker新手,或正在选择用于新项目的技术,请使用docker stack。

5、Docker Stack常用命令

命令描述
docker stack deploy部署新的堆栈或更新现有堆栈
docker stack ls列出现有堆栈
docker stack ps列出堆栈中的任务
docker stack rm删除一个或多个堆栈
docker stack services列出堆栈中的服务

​ 推荐实验: https://blog.csdn.net/huangjun0210/article/details/86502021

6、swarm网络细节

在 Swarm Service 中有三个重要的网络概念:

  • Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信。
  • ingress network 是一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有IP地址,选择其中的一个,并通过 ingress 网络将请求路由到它。
    初始化或加入 Swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。
  • docker_gwbridge是一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。
    docker_gwbridge 网络在初始化或加入 Swarm 时自动创建。大多数情况下,用户不需要自定义配置,但是 Docker 允许自定义。
名称类型注释
docker_gwbridgebridgenone
ingressoverlaynone
custom-networkoverlaynone
  • docker_gwbridge和ingress是swarm自动创建的,当用户执行了docker swarm init/connect之后。
  • docker_gwbridge是bridge类型的负责本机container和主机直接的连接
  • ingress负责service在多个主机container之间的路由。
  • custom-network是用户自己创建的overlay网络,通常我们都需要创建自己的network并把service挂在上面。

ingress网络。vip(虚拟ip模式)

2022-10-04T13:02:10.png

https://docs.docker.com/engine/swarm/ingress/

查看网络的基本环境

yum install bridge-utils -y    ##以后就可以brctl show 查看网关
iptables -nL -t nat   ##查看转发规则

ln -s /var/run/docker/netns /var/run/netns ## 看容器创建的两个Net Namespace

ip netns ##查看Net Namespace
ip netns exec xxx ip add  ##查看mynet网络命名空间下的网卡情况。
ip netns exec xxx brctl show ##查看mynet网络空间下网桥挂载情况可以看出veth0挂到了br0网桥上。

Docker Compose安装ES集群实战:

https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docker.html

Docker swarm 中的LB分为两种情况:

  1. Ingress Load Balancing:暴露端口方式的负载均衡。产生虚拟ip。转发链。
  2. Internal Load Balancing:内部的负载均衡。通过service的名字也可以访问吗?

自定义Service

  • the port where the swarm makes the service available outside the swarm

    • docker service -p 8080:80
  • an overlay network for the service to connect to other services in the swarm

    • docker service --network ?;同一个网络的跨机通讯
  • CPU and memory limits and reservations

    • docker service create

      --limit-cpu decimal                  Limit CPUs
      --limit-memory bytes                 Limit Memory
      
  • a rolling update policy

    • docker service create --update-delay 10s --update-parllelism 2
  • the number of replicas of the image to run in the swarm

    • docker service create --replicas 3 --name nginx nginx:1.19

Replicated and global services

2022-10-04T13:02:25.png

调整service以什么方式运行

--mode string                        
Service mode (replicated or global) (default "replicated")

docker service create --mode replicated --name mytom tomcat:7 默认的


docker service create --mode global --name haha alpine ping baidu.com
#场景?日志收集
每一个节点有自己的日志收集器,过滤。把所有日志最终再传给日志中心
服务监控,状态性能。
docker service create --name myredis --network myswarm-net redis
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
93: eth0@if94: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:01:03 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.3/24 brd 10.0.1.255 scope global eth0
       valid_lft forever preferred_lft forever
95: eth1@if96: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth1;都是本机的
       valid_lft forever preferred_lft forever
 "Endpoint": {
            "Spec": {
                "Mode": "vip"
            },
            "VirtualIPs": [
                {
                    "NetworkID": "xm5bv9m1yb5q5kfwl5sgbed0j",
                    "Addr": "10.0.1.2/24"  #集群访问redis拿这个可以用
                }
            ]
        }
ping 容器的集群ip(10.0.1.3),service的集群vip(10.0.1.2),serviceName都通
3redis副本以后;容器ip  10.0.1.8、10.0.1.3、10.0.1.9。
无论多少个副本。一个service虚拟ip是固定的。负载均衡的方式。
建立redis集群。一个虚拟ip。sb应用和redis集群只要在同一个网络。直接写10.0.1.2,serviceName




docker service create --name mynettomcat --network myswarm-net tomcat
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
93: eth0@if94: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:0a:00:01:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.1.6/24 brd 10.0.1.255 scope global eth0
       valid_lft forever preferred_lft forever
95: eth1@if96: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever
   docker service  inspect  mynettomcat
    "Endpoint": {
            "Spec": {
                "Mode": "vip"
            },
            "VirtualIPs": [
                {
                    "NetworkID": "xm5bv9m1yb5q5kfwl5sgbed0j",
                    "Addr": "10.0.1.5/24"
                }
            ]
        }

     10.0.1.0/24
#1、他们两个能互相访问吗?有哪些方式。ip?serviceName?

#2、vip,dnsrr
 docker service update --endpoint-mode dnsrr myredis
 # docker inspect service就没vip了想要负载均衡。只能serviceName;
 外部端口暴露负载均衡ingress。内部集群负载。vip。dnsrr

1、给docker集群部署服务的两种方式

docker service create xxxxx

2、使用compose文件

docker-compose up -d -c wordpress-compose.yaml;
效果:单机部署。自己产生默认的网络
docker stack deploy wordpress-compose.yaml;#集群部署,compose里面的所有服务会被发配到集群的各个地方
#写好docker-compose文件。运维人员部署即可。
version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
  
#扩展。
集群下的数据一致。
redis,mysql等这些集群。数据本身挂载到本机(没有任何问题)。高可用,就是做mysql的集群。设置好集群内的数据同步,这是mysql集群技术解决的问题。而不是数据卷挂载解决的问题。
应用的资源文件。才应该考虑数据卷的集群情况下,如果本机挂载就不一致了。自己文件系统。
nfs;/abc  ---> 远程的:/haha


Dockerfile
VOLUME ["/sss"] -->映射到docker /var/lib/docker/volumes

2022-10-04T13:05:29.png

2022-10-04T13:05:40.png

Docker Secret与Config

Secret

生产环境下,为了安全,我们不能把各项目的配置密码写入到配置文件

我们可以引入docker的secret方式保护密码。

场景

  • 用户名密码
  • SSH Key
  • TLS认证
  • 任何别人不想看到的数据

1、创建一个密码secret

2、用完就删

3、哪个服务想要使用只要暴露给他即可。

1、如何声明

#文本模式
printf 123456 | docker secret create my_secret -
echo "adminadmin" | docker secret create my-pwd -
#文件模式
docker secret create my_secret ./pwd
#Secret会基于raft在master主机之间同步。

2、如何使用

secret可以分配给一个service,就可以使用,secret在容器内部看起来是个文件,实际上在内存中

#1、普通情况
docker service create --name mysql --secret mysql_pwd -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pwd -p 3306:3306 mysql:5.7

#2、compose文件
version: "3"
services:
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    secrets:
      - mysql_pwd
    enviroment:
      - MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_pwd

原理:我们使用--secret mysql_pwd以后,secret密码文件就会被解码保存到容器内部的/run/secrets/secretname中。这样我们就可以在容器中任意使用。但是外部无感知。

不管怎么使用,secret最好提前创建好。到时候声明使用就行。其实是在内存中的。整个集群manager是利用raft同步的

config

1、如何声明

docker config create [OPTIONS] CONFIG file|-
docker config create redis.conf redis.conf
# 使用文件方式创建
docker service create --config redis.conf --name redis redis
#最终会被映射到容器的根目录。以后修改容器的启动命令即可


#配置中心
#部署100个redis副本。到100个服务器。他们配置文件都一样
#config内容base64编码,是可以inspect出来的。
secret文件是在容器中 /run/secrets/xxxx 暴露的
config默认是在根目录暴露的。

2、如何使用

#指定位置
docker service create --name redis \
  --config source=redis-conf,target=/etc/redis/redis.conf,mode=0400 redis:3.0.6
  
#2、compose文件
version: "3"
services:
  mysql:
    image: redis
    ports:
      - 6379:6379
    config:
      - mysql_pwd
    enviroment:
      - MYSQL_ROOT_PASSWORD_FILE: /

https://docs.docker.com/compose/compose-file/#configs

3、补充Label的使用

# 我们讨论了 Service 部署的两种模式:global mode 和 replicated mode。无论采用 global mode 还是 replicated mode,副本运行在哪些节点都是由 Swarm 决定的,作为用户我们有没有可能精细控制 Service 的运行位置呢?
答:能,使用 label

逻辑分两步:
1、为每个 node 定义 label。
2、设置 service 运行在指定 label 的 node 上。

docker node update --label-add env=test 节点1
docker node update --label-add env=prod swarm-worker2
docker service create \
      --constraint node.labels.env==test \
      --replicas 3 \
      --name my_web \
      --publish 8080:80 \
      httpd
      
#更新 service,将其迁移到生产环境:
docker service update --constraint-rm node.labels.env==test my_web  
docker service update --constraint-add node.labels.env==prod my_web

8、扩展阅读

1、vxlan https://blog.csdn.net/tony_vip/article/details/100097245

2、lvs https://blog.csdn.net/tony_vip/article/details/104224374

其他填坑

2022-10-04T13:03:20.png

Service Mode:服务模式。 Endpoint Mode:端点模式

1、集群的所有操作必须在manager节点执行

2、机器数量决定的业务体量

3、service就是一个业务,真正是以容器的方式运行在docker机器。服务副本指容器数量

​ 打日志的时候,加上机器名就行。

Reference

  • 《Docker 即学即用》/ (美)马迪亚斯(Matthias,K.),(美)凯恩(Kane,S.P.) 著;安道译. —— 北京:中国电力出版社,2015.12

https://docs.docker.com/compose/

Dockerfile。商城。拆分很多微服务。10微服务

购物车微服务+Redis+MySQL = 一套服务(自动化的全套部署,全套下线)。交给Docker Compose【编排】。一个整套的application会有非常多的service

一次性的将所有相关联的服务自动部署。

前面我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker build、docker run 等命令操作容器。然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知。批量的维护整套应用

使用 Docker Compose 可以轻松、高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具

Compose的三步最佳实战:

  1. 定义自己应用的 Dockerfile 文件。为了在anywhere进行构建。
  2. 使用 docker-compose.yml定义我们服务。这一整套服务可以一起在一个隔离环境运行.
  3. 运行 docker-compose up 就可以启动整个app.

总结:批量服务编排。docker-compose.yml声明服务的规则。

单机环境。

1、安装

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

docker-compose version

2、体验

1、创建一个测试应用

#1、Create a directory for the project:

mkdir composetest
cd composetest

#2、Create a file called app.py in your project directory and paste this in:
import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)


def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)


@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)
#3、Create another file called requirements.txt in your project directory and paste this in:
flask
redis

2、创建Dockerfile

#In your project directory, create a file named Dockerfile and paste the following:
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]

3、在Compose file里定义服务

#Create a file called docker-compose.yml in your project directory and paste the following:
version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

4、Compose构建和运行应用

docker-compose up -d
#访问 http://localhost:5000/ 测试效果

5、效果

自己打包---》dockerfile--》结合docker-compose

1、创建网络

​ 默认的网络:1998ee0450ee composetest_default bridge local

version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"
#默认两个服务都用一个网络,是contextName_default;web里面可以使用redis的hostname访问
#cache = redis.Redis(host='redis', port=6379)
#默认每一个启动的容器 contextName_serviceName_1
docker network inspect composetest_default  
#效果:这个网络里面有。两个容器
#docker service ls #查看当前的服务。docker集群下,我们能看到所有的服务 容器的名_num。代表第几个副本。

集群状态下;compose更帅。我们可以直接定义服务在多个机器都有副本。

2022-10-04T12:50:49.png

2、构建每个镜像

3、创建两个容器在同一网络,我们可以使用hostname访问

docker-compose帮我们自定的部署了pyweb,redis,并且pyweb能访问redis。pyweb的5000浏览器也能访问

2022-10-04T12:51:11.png

2022-10-04T12:51:47.png

整个docker:

1、dockerfile

2、docker-compose

3、docker二次开发,如何更换底层存储驱动,如何自定义docker的网络。。。

详情:https://docs.docker.com/compose/compose-file/#reference-and-guidelines

#语法
三层
version: ""
services:  #定义很多服务
    服务1:
      #当前服务配置
    服务2:
      #当前服务配置
#服务要用的网络、卷,等其他全局规则,定义
volumes:
networks:
configs:
secrets:



networks:
  outside:
    external: true #外面创建好了,docker-compose不自动创建
如果自定义用了网络。卷等,都必须声明
version: "3"
services:
  java-app: 
     build: .
     ports:
       - "9000:8080"
     depends_on:
       - mysql
     command: java -jar /app.jar --spring.datasource.url=jdbc:mysql://mysql:3306/wps?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
     networks:
       - app-network
  mysql:
    image: mysql:5.7
    environment:
       MYSQL_ROOT_PASSWORD: 123456
    networks:
       - app-network

networks:
  app-network: {}


docker-compose up -d
docker-compose up -d --build #再触发一下手动构建


随便网上一个项目。dockerfile+docker-compose 一键搞定
mysql dockerfile-->run 网上的项目拉下来,把的sql文件导入数据。


docker-compose替代了dockerfile。完全可以(镜像存在)自定义的镜像 dockerfile+docker-compose。

整个docker-compose up/down/rm 单机情况下的编排

app-redis。用同一个网络。

集群情况。官方默认docker-swarm

docker 5个。 2主(HA) 3从(工作节点)

5、概念

工程、服务、容器

  • Docker Compose 将所管理的容器分为三层,分别是工程(project)、服务(service)、容器(container)
  • Docker Compose 运行目录下的所有文件(docker-compose.yml)组成一个工程,一个工程包含多个服务,每个服务中定义了容器运行的镜像、参数、依赖,一个服务可包括多个容器实例

6、实战-使用Compose构建一个wordpress应用

https://docs.docker.com/compose/wordpress/

Docker仓库(私有仓库)

阿里云

开通阿里云容器镜像服务

l8u4n4s4.png

#阿里云下载镜像,需要填写前缀
docker pull registry.cn-shenzhen.aliyuncs.com/ali/mysql:[镜像版本号]

ali:命名空间
mysql:镜像仓库
  • 创建命名空间
  • 创建镜像仓库

Harbor

网络高级

#安装Es+kibana;kibana得指定es地址,
#sb-book-crud-service   mysql

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

l8u4nks6.png

Linux虚拟网络技术。

Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);

Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

原理:

1、每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。桥接网卡

2、没启动一个容器linux主机多了一个虚拟网卡。

3、docker run -d -P --name tomcat --net bridge tomcat:8

#1、docker0网络的特点。,
    默认
    域名访问不通
    --link 域名通了,但是删了又不行
    
#2、可以让容器创建的时候使用自定义网络
     1、自定义创建的默认default "bridge"
     2、自定义创建一个网络网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
    所有东西实时维护好,直接域名ping同
    3、理解网络。

docker network connect [OPTIONS] NETWORK CONTAINER

跨网络连接别人就用
docker network connect mynet tomcat
效果:
    1、自定义网络,默认都可以用主机名访问通
    2、跨网络连接别人就用 docker network connect mynet tomcat

1、容器启动,指定容器ip。 docker run --ip 192.168.0.3 --net 自定义网络  
2、网络。docker network create --subnet 指定子网范围  --driver bridge 所有东西实时维护好,直接域名ping同
3、docker compose。

image-20200425220210857

1、网络的创建过程

Docker创建一个容器的时候,会具体执行以下操作:

  1. 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中
  2. 本地主机一段的虚拟接口连接到默认的docker0网桥或者指定网桥上,并具有一个以veth开头的唯一名字
  3. 容器一段的虚拟接口将放到新创建的容器中,并修改名字为eth0。这个接口只在容器的命名空间可见
  4. 从网桥的可用地址段中获取一个空闲的地址分配给容器的eth0(如:172.17.0.2/16),并配置默认路由网关为docker0网卡的内部接口docker0的IP地址(如:172.17.42.1/16)

完成以上,容器就可以使用它所能看到的eth0虚拟网卡来连接其他容器和访问外部网络。

网络模式

网络模式配置说明
bridge模式--net=bridge默认值,在Docker网桥docker0上为容器创建新的网络栈
none模式--net=none不配置网络,用户可以稍后进入容器,自行配置
container模式--net=container:name/id容器和另外一个容器共享Network namespace。
kubernetes中的pod就是多个容器共享一个Network namespace。
host模式--net=host容器和宿主机共享Network namespace
用户自定义--net=自定义网络用户自己使用network相关命令定义网络,
创建容器的时候可以指定为自己定义的网络

实验测试网络互连

  • 大家重点理解veth pair技术
  • --link是容器在默认网络模式下,可以互相使用容器名ping通的
  • 如果容器创建时使用自定义网络,不使用--link也是可以ping通相互的容器名
  • --link 生产一般不用,我们可以使用自定义网络的方式
  • docker network connect

部署一个集群(redis)

Dockerfile

Dockerfile指南:https://docs.docker.com/engine/reference/builder/

事情:nginx。tomcat。mysql。镜像从哪里来?

我们自己如何做一个镜像。微服务。SpringBoot。上云部署。最方便是Docker。

微服务打包成镜像。任何装了Docker。都可以下载使用。

应用-->Dockerfile--->打包成镜像--->上传到仓库(公有仓库,私有仓库)--->下载镜像--->启动运行。

移植:扩充服务器。

如何得到一个镜像

1、自己做的Dockefile

https://docs.docker.com/engine/reference/builder/

#nginx Dockerfile的示例
#alpine:3.11超迷你的linux 4mb;
#alpine:3.11 linux全目录 基于宿主机linux的一个统一接口。cpu,mem。主机。
FROM alpine:3.11

LABEL maintainer="NGINX Docker Maintainers <[email protected]>"

#环境
ENV NGINX_VERSION 1.18.0
ENV NJS_VERSION   0.4.0
ENV PKG_RELEASE   1

RUN set -x \
# create nginx user/group first, to be consistent throughout docker variants
    && addgroup -g 101 -S nginx \
    && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \
    && apkArch="$(cat /etc/apk/arch)" \
    && nginxPackages=" \
        nginx=${NGINX_VERSION}-r${PKG_RELEASE} \
        nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \
        nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \
        nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \
        nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \
    " \
    && case "$apkArch" in \
        x86_64) \
# arches officially built by upstream
            set -x \
            && KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \
            && apk add --no-cache --virtual .cert-deps \
                openssl \
            && wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \
            && if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \
                echo "key verification succeeded!"; \
                mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \
            else \
                echo "key verification failed!"; \
                exit 1; \
            fi \
            && apk del .cert-deps \
            && apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \
            ;; \
        *) \
# we're on an architecture upstream doesn't officially build for
# let's build binaries from the published packaging sources
            set -x \
            && tempDir="$(mktemp -d)" \
            && chown nobody:nobody $tempDir \
            && apk add --no-cache --virtual .build-deps \
                gcc \
                libc-dev \
                make \
                openssl-dev \
                pcre-dev \
                zlib-dev \
                linux-headers \
                libxslt-dev \
                gd-dev \
                geoip-dev \
                perl-dev \
                libedit-dev \
                mercurial \
                bash \
                alpine-sdk \
                findutils \
            && su nobody -s /bin/sh -c " \
                export HOME=${tempDir} \
                && cd ${tempDir} \
                && hg clone https://hg.nginx.org/pkg-oss \
                && cd pkg-oss \
                && hg up -r 474 \
                && cd alpine \
                && make all \
                && apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \
                && abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \
                " \
            && cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \
            && apk del .build-deps \
            && apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \
            ;; \
    esac \
# if we have leftovers from building, let's purge them (including extra, unnecessary build deps)
    && if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \
    && if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \
    && if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \
# Bring in gettext so we can get `envsubst`, then throw
# the rest away. To do this, we need to install `gettext`
# then move `envsubst` out of the way so `gettext` can
# be deleted completely, then move `envsubst` back.
    && apk add --no-cache --virtual .gettext gettext \
    && mv /usr/bin/envsubst /tmp/ \
    \
    && runDeps="$( \
        scanelf --needed --nobanner /tmp/envsubst \
            | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
            | sort -u \
            | xargs -r apk info --installed \
            | sort -u \
    )" \
    && apk add --no-cache $runDeps \
    && apk del .gettext \
    && mv /tmp/envsubst /usr/local/bin/ \
# Bring in tzdata so users could set the timezones through the environment
# variables
    && apk add --no-cache tzdata \
# Bring in curl and ca-certificates to make registering on DNS SD easier
    && apk add --no-cache curl ca-certificates \
# forward request and error logs to docker log collector
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log \
# make default server listen on ipv6
    && sed -i -E 's,listen       80;,listen       80;\n    listen  [::]:80;,' \
        /etc/nginx/conf.d/default.conf

EXPOSE 80

STOPSIGNAL SIGTERM

CMD ["nginx", "-g", "daemon off;"]
# Dockerfile复原了我们在linux上安装nginx的过程。

2、别人给我们准备好的文件。xxx.tar。可以通过硬盘传输使用。

1586440635817

1、创建项目dockerfile

2、上传项目到服务器。

3、进入项目,构建镜像到本地仓库;

  • docker build -t nginx:1.0 -f ./Dockerfile . 别忘了最后的小数点。
  • docker images 查看镜像
  • docker exec -it 容器id /bin/bash;进入容器,修改容器
  • docker commit -a “icoding” -m “nginxxx” 容器id mynginx:2.0

    • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    • OPTIONS说明:

      • -a :提交的镜像作者;
      • -c :使用Dockerfile指令来创建镜像;
      • -m :提交时的说明文字;
      • -p :在commit时,将容器暂停。
  • docker login : 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub

    • docker login -u 用户名 -p 密码
  • docker logout : 登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub

4、推送镜像到docker hub

  • 标记镜像,docker tag local-image:tagname username/new-repo:tagname
  • 上传镜像,docker push username/new-repo:tagname

5、保存镜像,加载镜像

  • 可以保存镜像为tar,使用u盘等设备复制到任意docker主机,再次加载镜像
  • 保存:docker save spring-boot-docker -o /home/spring-boot-docker.tar
  • 加载:docker load -i spring-boot-docker.tar

6、阿里云操作

  • 登录阿里云,密码就是开通镜像仓库时 的密码

    • docker login --username=icoding registry.cn-hangzhou.aliyuncs.com
  • 拉取镜像

    • docker pull registry.cn-hangzhou.aliyuncs.com/icoding/i-nginx:v1.0
  • 推送镜像

    • docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/icoding/icoding-nginx:v2
    • docker push registry.cn-hangzhou.aliyuncs.com/icoding/icoding-nginx:v2

2、Dockerfile详解

Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。

一般而言,Dockerfile可以分为四部分

基础镜像信息 维护者信息 镜像操作指令 启动时执行指令

指令说明
FROM指定基础镜像
MAINTAINER指定维护者信息,已经过时,可以使用LABEL maintainer=xxx 来替代
RUN运行命令 v
CMD指定启动容器时默认的命令 v
LABEL指定生成镜像的元数据标签信息 v
EXPOSE声明镜像内服务监听的端口 v
ENV指定环境变量,可以在docker run的时候使用-e改变 v
ADD复制指定的src路径下的内容到容器中的dest路径下,src可以为url会自动下载,可以为tar文件,会自动解压
COPY复制本地主机的src路径下的内容到镜像中的dest路径下,但不会自动解压等
ENTRYPOINT指定镜像的默认入口.运行命令 v
VOLUME创建数据卷挂载点
USER指定运行容器时的用户名或UID
WORKDIR配置工作目录,为后续的RUN、CMD、ENTRYPOINT指令配置工作目录
ARG指定镜像内使用的参数(如版本号信息等),可以在build的时候,使用--build-args改变 v
OBBUILD配置当创建的镜像作为其他镜像的基础镜像是,所指定的创建操作指令
STOPSIGNAL容器退出的信号值
HEALTHCHECK健康检查
SHELL指定使用shell时的默认shell类型

1、RUN、CMD、ENTRYPOINT区别

  1. RUN 执行命令并创建新的镜像层RUN 经常用于安装软件包(在构建镜像时运行的)。
  2. CMD 设置容器启动后默认执行的命令及其参数但 CMD 能够被 docker run 后面跟的命令行参数替换。
  3. ENTRYPOINT 配置容器启动时运行的命令。
  4. 以上命令都可以使用shell或者exec方式执行
  5. CMD ["executable","param1","param2"] (exec form, this is the preferred form)
  6. CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
  7. CMD command param1 param2 (shell form)

2、shell和exec方式

1.  shell 是  /bin/sh -c <command>的方式,

2.  exec ["/bin/sh","-c",command] 的方式== shell方式
eg:shell方式

ENV name icoding  
ENTRYPOINT echo "Hello, $name" 
#输出 Hello icoding

ENTRYPOINT ["/bin/echo", "Hello, $name"]
#输出 Hello $name

ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
#输出 Hello icoding

##建议:CMD 和 ENTRYPOINT 推荐使用 Exec 格式因为指令可读性更强更容易理解。RUN 则两种格式都可以。exec的时候要获取环境变量等值,就用/bin/sh -c 即可。
No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

3、实战Dockerfile

#1、ping命令小工具。
编写Dockerfile-->打包镜像--->根据这个镜像启动容器使用容器的功能
docker build -t hello .
-t:tag标签。镜像名字
.:在当前目录下工作
默认.这个目录下就得有一个 Dockerfile
FROM alpine
CMD ping baidu.com

#2、文件名不是Dockerfile。用-f 指定
docker build -f Dockerfile2 -t hello:v1.0 .
docker run -d --name hello hello;

#3、默认构建出来的镜像,放到了我们的本地镜像仓库。
    1)、登陆到dockerhub
    2)、dockehub国外,就算能Push,非常慢。阿里云加速的是下载。
    
#4、把这个镜像发布到Docker hub
    1)、docker login -u icodingallen;登陆到docker hub
    2)、docker push nginx:v1.0;推送过去。
    太慢了
#5、搭建私有的镜像仓库。使用阿里云的镜像仓库(免费)。
    1)、docker login [email protected] registry.cn-hangzhou.aliyuncs.com

为了团队自治。只能看到自己的仓库的所有镜像。namespace;
创建镜像仓库。保存镜像各种版本,book: 1 2 3 4 5
docker tag hello:v1.0 registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.3
docker push registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.3

image-20200427213352196

image-20200427215730365

docker.io/libarary/hello:latest

registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.0

镜像---》打包--》上传。

5、Dockerfile区分一些易混淆的指令

1、USER 执行cmd等之类命令的使用那个用户

alpine  sudo   gosu
FROM centos
RUN groupadd -r abc && useradd -r -g abc aaa
USER aaa
CMD whoami
# CMD 就是容器启动以后要执行的命令

2、ARG、ENV

  • The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build :arg在构建期间。docker build
  • The environment variables set using ENV will persist when a container is run from the resulting image. You can view the values using docker inspect, and change them using docker run --env =. env在运行是可以用到的
FROM alpine

ARG bbb haha
ENV abc 666

CMD echo $bbb
容器运行的时候arg的东西拿不到

CMD echo $abc
容器运行的时候env的能拿到


FROM alpine

ARG bbb haha
ENV abc=$bbb

CMD echo $abc

ARG指定的值,在镜像构建的后面位置,构建期间都可以使用到。

改变这些值行不行
docker build -f Dockerfile-arg-env -t file-arg --build-arg bbb=888 --build-arg abc=777 .
结果888 


# 构建时 bbb=888 abc=777 ,cmd打印888.原因 构建时不能改变env
# 运行时 
\ARGENV
build时√。--build-arg改变 构建参数(ARG声明)生效,能不能改(不能)
运行时不生效生效。能改 -e abc

最佳实战:

ARG:定义一些版本信息

​ FROM alpine

​ ARG version=1

​ RUN yum install nginx:$version

Env:运行时的环境变量。

ENV env = --spring.profile.active=prod

​ -e修改。sb java -jar xxx.jar $env

3、ADD和COPY

#构建了一个SpringBoot镜像。 xxx.jar 
/opt

docker build -t hello .

ADD:将当前目录下的内容放到镜像里面一起打包。

COPY:将当前目录下的内容放到镜像里面一起打包。

ADD ["<src1>","<src2>","<dest>"]  dest:容器里面的目录
可以指定很多种路径地址。自动下载,解压复制。
FROM alpine

ADD hello.tar /opt/hello

COPY hello.tar /opt/world/

CMD echo "1234"

这个东西构建的镜像为什么docker run -d 不行。因为容器运行的是ech 1234;
没有一个守护进程一直运行。
CMD ping baidu.com

4、VOLUME和WORKDIR

VOLUME:指定容器需要挂载的卷
WORKDIR:工作目录。
    1、以后的其他命令在这个目录里面运行
    2、exec进去都默认来到了 WORKDIR 指定的目录。sh
    docker run -it --rm file-volume sh
    
WORKDIR


WORKDIR /root  == RUN cd /root

挂载麻烦。自动挂载。
FROM alpine

WORKDIR /opt/a

VOLUME /opt/b

COPY hello.txt .

ADD hello.tar /opt/b

CMD whoami

volume声明的挂载目录,即使容器运行的时候,不用-v进行挂载。docker也会自动的进行匿名挂载。
nginx:

5、RUN、CMD、ENTRYPOINT

相同点:运行命令

不同点:

​ RUN:在构建镜像的时候运行的命令

CMD、ENTRYPOINT:在容器启动运行的命令

测试RUN;

#想构建一个具有git功能的镜像。
FROM centos

RUN yum install -y git

WORKDIR /opt/data

RUN git clone https://gitee.com/lanoox/luject.git

VOLUME /opt/data
CMD echo "git clone success"
#CMD 容器运行的时候CMD的命令才执行。

image-20200429201703690

image-20200429201639095

image-20200429202237672

相同的镜像layer层发生变化,只有这层变化。

  • -RUN指令的所有命令都在镜像docker build期间就执行
  • CMD和ENTRYPOINT在容器启动时运行

    • CMD 容器运行的时候CMD的命令才执行。docker run -it --rm file-run bash 能进容器中
    • 替换为ENTRYPOINT。虽然指令运行了。但是 docker run -it --rm file-run bash 。最后的bash没有进去,失效了。

无论是CMD还是ENTRYPOINT还是RUN

  • RUN (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows) RUN yum install -y git;/bin/sh -c可以动态获取一些变量
  • RUN ["executable", "param1", "param2"] (exec form);无法动态获取一些变量
FROM centos

ARG soft=git
RUN ["yum install","-y","$soft"] #这是错误的。因为非`/bin/sh -c`方式,用不到前面声明的ARG,ENV

WORKDIR /opt/data

RUN git clone https://gitee.com/lanoox/luject.git

VOLUME /opt/data
ENTRYPOINT echo "git clone success"

image-20200429203242832

# bash-c 和 数组方式的区别,  修改后的;安装正确。
FROM centos

ARG soft=git
RUN ["/bin/sh","-c","yum install -y $soft"]
#-c command:后免是完整命令
WORKDIR /opt/data

RUN git clone https://gitee.com/lanoox/luject.git

VOLUME /opt/data
ENTRYPOINT echo "git clone success"

RUN、CMD、ENTRYPOINT都支持一下两种方式

The exec form, which is the preferred form:

ENTRYPOINT ["executable", "param1", "param2"]

The shell form:

ENTRYPOINT command param1 param2

总结:

  • 如果运行命令是。[]方式,默认不是bash -c就无法用变化,普通的方式RUN yum -install -y $soft可以使用变量。
  • CMD、ENTRYPOINT的最佳实战

    • Dockerfile文件必须至少有一个 CMD 或者ENTRYPOINT 命令.
    • ENTRYPOINT 用来定义容器如何运行.
    • CMD 应该被用来作为给ENTRYPOINT 传递。默认参数的一种方式
    • CMD 将会被覆盖,容器运行时指定参数的时候. ENTRYPOINT 命令不会被覆盖。
    • CMD多个只会有一个生效。
    • ENTRYPOINT :不被传入的指令覆盖,但是多个也只有一个生效。

    为什么我的指令Dockerfile写CMD的时候,docker run -it --rm file-run bash可以进控制台,而ENTRYPOINT 不行?

    运行效果:

    • Dockerfile是CMD;没打印git clone success。但是bash生效。

    image-20200429205557526

    • Dockerfile 是 ENTRYPOINT;打印了git clone success但是没有进容器(bash没生效)

    image-20200429205729145

  • 混写。CMD + ENTRYPOINT
FROM centos

ARG soft=git
RUN ["/bin/bash","-c","yum install -y $soft"]

WORKDIR /opt/data

RUN git clone https://gitee.com/lanoox/luject.git

VOLUME /opt/data


CMD ["nginx"] #CMD给entrypoint提供参数
ENTRYPOINT ["yum","install","-y"]


运行:
docker run -it --rm file-run maven
FROM centos

ARG soft=git
RUN ["/bin/bash","-c","yum install -y $soft"]

WORKDIR /opt/data

RUN git clone https://gitee.com/lanoox/luject.git

VOLUME /opt/data


CMD ["","","",""] #可以放空
ENTRYPOINT ["/bin/sh","-c","yum install -y"]

#容器启动就是yum install -y "";自己启动命令加上git
CMD 后面有N参数。传了参数替换N个还是最后一个?
docker run -it --rm file-run maven  CMD ["maven"]  对
docker run -it --rm file-run maven  CMD [“”,“”,"maven"] 错

目的:构建镜像。SpringBoot编写的微服务,怎么做镜像?

1、运行的业务的目标环境?SB服务。java环境。FROM

2、怎么启动业务的。得到jar包,java -jar xxx.jar --spring.profile.active=prod --server.port=8080;决定镜像的ENTRYPOINT怎么写。docker exec?docker run(第一次容器启动要执行)?

docker exec haha -it bash【和entrypoint,cmd没啥关系】;

3、业务运行的时候需要啥?java。jar。jar包就想办法放进镜像中。COPY 。ADD

4、业务的那些数据是需要做持久化。VOLUME怎么写。

FROM java:8


#服务器只有dockerfile和jar在一起
COPY *.jar /app.jar

#即使运行没有-v,也会匿名挂载
VOLUME ["/logs"]

CMD ["--server.port=8080"]

EXPOSE ["8080"]

ENTRYPOINT ["java","-jar","/app.jar"]

4、idea快速整合使用

作为一个了解。

1、 Docker开启远程访问

#修改该Docker服务文件
vi /lib/systemd/system/docker.service
#修改ExecStart这行,将原来注释,加上这个命令
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
#重新加载配置文件
systemctl daemon-reload
#重启服务
systemctl restart docker.service
#查看端口是否开启
netstat -nlpt #如果找不到netstat命令,可进行安装。yum install net-tools
#直接curl看是否生效
curl http://127.0.0.1:2375/info

2、IDEA安装Docker插件

1586754551705

3、IDEA配置docker

1586754754747

4、也可以整合自己的私有镜像仓库

1586755152991

==可以提供非常方便的部署功能==

1586755804914

docker build -t hello-java . && docker run -p 88:8080 -v /logs:/logs --name hello-666 hello-java

Dockerfile解耦应用的开发与部署。

maven插件再把部署流程一配置就不解耦。,

应用。代码变了改应用。部署只改Dockerfile。

maven。代码部署放在了一个完整的生命周期。运维人员想要改网络部署等配置,还得改pom。CICD只需要一个Dockerfile。

5、docker-maven-plugin

市面上docker-maven-plugin太多,我们推荐一个 docker-maven-plugin,照着文档使用就行。不管使用哪一种docker插件来构造image,都比不上直接用Dockerfile编写简单,而且可复用,不用学习不同插件不同的构造规则。

最好给自己的Docker服务器配置阿里云镜像加速,否则经常导致镜像下载不来的情况

fabric8io的有两大功能:

  1. 构造并推送Docker镜像
  2. 启动和停止Docker容器
<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.33.0</version>

    <!--全局配置-->
    <configuration>
        <!--这一部分是为了实现对远程docker容器的控制-->
        <!--docker主机地址,用于完成docker各项功能,注意是tcp不是http!-->
        <dockerHost>tcp://公网IP:2376</dockerHost>
        <!--docker远程访问所需证书地址,如果docker远程主机没有启用TLS验证则不需要配证书-->
        <certPath>${project.basedir}/docker/ssh</certPath>

        <!--这一部分是为了实现docker镜像的构建和推送-->
        <!--registry地址,用于推送,拉取镜像,我这里用的是阿里的registry-->
        <registry>registry.cn-shenzhen.aliyuncs.com</registry>
        <!--认证配置,用于私有registry认证,如果忘记了可以去阿里的registry查看-->
        <authConfig>
            <push>
                <username>这里填registry的用户名</username>
                <password>这里填registry的密码</password>
            </push>
        </authConfig>

        <!--镜像相关配置,支持多镜像-->
        <images>
            <!-- 单个镜像配置 -->
            <image>
                <!--镜像名(含版本号)-->
                <name>命名空间/仓库名称:镜像版本号</name>
                <!--别名:用于容器命名和在docker-compose.yml文件只能找到对应名字的配置-->
                <alias>${project.name}</alias>
                <!--镜像build相关配置-->
                <build>
                    <!--使用dockerFile文件-->
                    <dockerFile>${project.basedir}/docker/${project.name}</dockerFile>
                </build>
                <!--配置docker-compose文件-->
                <external>
                    <type>compose</type>
                    <basedir>${project.basedir}/docker</basedir>
                    <composeFile>docker-compose.yml</composeFile>
                </external>
                <!--容器run相关配置-->
                <run>
                    <!--配置运行时容器命名策略为:别名,如果不指定则默认为none,即使用随机分配名称-->
                    <namingStrategy>alias</namingStrategy>
                </run>
            </image>
        </images>
    </configuration>
</plugin>
maven指令功能
docker:start创建和启动容器
docker:stop停止并销毁容器
docker:build构建镜像
docker:watch自动进行重建和重启
docker:push将镜像推送到registry
docker:remove从本地docker主机删除镜像
docker:logs显示容器日志
docker:source将docker build archive附加到Maven项目
docker:save将镜像保存到文件
docker:volume-create创建卷以在容器之间共享数据
docker:volume-remove删除创建的卷
#打包到容器运行的完整流程
mvn clean package docker:stop docker:remove docker:build docker:run 
#不是每一次运行都要推送镜像,如果要的话可以单独调用docker:push
mvn docker:push
#示例配置
<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.33.0</version>

    <configuration>
        <dockerHost>tcp://111.229.61.54:2375</dockerHost>
        <registry>registry.cn-shenzhen.aliyuncs.com</registry>
        <authConfig>
            <push>
                <username>icodingallen</username>
                <password>icoding123</password>
            </push>
        </authConfig>
        <images>
            <image>
                <name>icoding/icoding-docker:v1.2</name>
                <build>
<!--使用dockerFile文件 <dockerFile>${project.basedir}/docker/${project.name}</dockerFile>-->
                    <dockerFile>${project.basedir}/Dockerfile</dockerFile>
                </build>
                <run>
                    <ports>
                        <port>8080:8080</port>
                    </ports>
                </run>
            </image>
        </images>
    </configuration>
</plugin>
FROM java:8
LABEL maintainer=icoding
ADD target/*.jar /app.jar
EXPOSE 8080
CMD ["java","-jar","app.jar"]
@RestController
public class HelloController {

    @Value("${project.version}")
    String ver;
    @Value("${project.name}")
    String name;

    @GetMapping("/")
    public String hello(){
        return "Hello Docker!"+ver+"=>"+name;
    }
}
#获取maven pom对象的相关属性值。在springboot中获取如下
[email protected]@
[email protected]@
#在pom文件中直接使用${project.xxxx},按照对象属性关系获取即可

安装MySQL

docker run -p 3306:3306 --name mysql \
-v /idata/mysql/log:/var/log/mysql \
-v /idata/mysql/data:/var/lib/mysql \
-v /idata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

docker exec -it mysql mysql -uroot -proot
#配置MySQL主从复制 
#创建master
docker run -p 3306:3306 --name mysql-master \
-v /idata/mysql/log:/var/log/mysql \
-v /idata/mysql/data:/var/lib/mysql \
-v /idata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
##配置文件
vim /idata/mysql/conf/my.cnf

[client]
default-character-set=utf8
 
[mysql]
default-character-set=utf8
 
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

server_id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=icoding_test

replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema

#创建Slaver,和master一致,配置文件修改如下即可
server_id=2
log-bin=mysql-bin
read-only=1
binlog-do-db=icoding_test

replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema

#配置matser
1、添加用来同步的用户
       GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';
2、查看master状态
   show master status\G;
 
#配置slaver
1、change master to master_host='mysql-master',master_user='backup',master_password='123456',master_log_file='mysql-bin.000003',master_log_pos=0,master_port=3306;
2、start slave;
3、show slave status\G;

安装Redis

mkdir -p /idata/redis/conf
touch /idata/redis/conf/redis.conf

docker run -p 6379:6379 --name redis -v /idata/redis/data:/data \
-v /idata/redis/conf:/etc/redis \
-d redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

redis 自描述文件:
https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf

#安装redis-cluster;3主3从方式,从为了同步备份,主进行slot数据分片
##单机情况下可以这样做。
## cluster-announce-ip 192.168.56.10 为自己服务器的ip
for port in $(seq 7001 7006); \
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 ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.26.65.131 
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOF
docker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
done
docker stop $(docker ps -a |grep redis-700 | awk '{ print $1}')
docker rm $(docker ps -a |grep redis-700 | awk '{ print $1}')

##建立集群
docker exec -it redis-7001 /bin/sh
redis-cli --cluster create 172.26.65.131:7001 172.26.65.131:7002 172.26.65.131:7003 172.26.65.131:7004 172.26.65.131:7005 172.26.65.131:7006 --cluster-replicas 1

redis-cli -c -h 192.168.56.10 -p 7006  # -c方式连接
cluster info ,cluster node;测试
#模拟网络分离的
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



docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 192.168.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \


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


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

docker exec -it redis-1 /bin/sh
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

安装ElasticSearch

mkdir -p /idata/es/config
mkdir -p /idata/es/data
echo "http.host: 0.0.0.0" >> /idata/es/config/elasticsearch.yml
chmod -R 777 /idata/es/ #保证权限
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /idata/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /idata/es/data:/usr/share/elasticsearch/data \
-v /idata/es/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.0.10:9200 -p 5601:5601 \
-d kibana:7.4.2
#安装Es集群
所有之前先运行:sysctl -w vm.max_map_count=262144
我们只是测试,所以临时修改。永久修改使用下面
#防止 JVM 报错
echo vm.max_map_count=262144 >> /etc/sysctl.conf
sysctl -p

##############3-master##########################
for port in $(seq 1 3); \
do \
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF >/mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name: my-es #集群的名称,同一个集群该值必须设置成相同的
node.name: es-master-${port} #该节点的名字
node.master: true #该节点有机会成为 master 节点
node.data: false #该节点可以存储数据
network.host: 0.0.0.0
http.host: 0.0.0.0 #所有 http 均可访问
http.port: 920${port}
transport.tcp.port: 930${port}
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: ["172.18.12.21:9301", "172.18.12.22:9302", "172.18.12.23:9303"] #设置集群中的 Master 节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7的新增配置;
cluster.initial_master_nodes: ["172.18.12.21"] #新集群初始时的候选主节点,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \ -p 920${port}:920${port} -p 930${port}:930${port} \ --network=mynet --ip 172.18.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \ -v
/mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/el
asticsearch.yml \ -v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data \ -v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins \ -d elasticsearch:7.4.2
done




#######################3-node#######################
for port in $(seq 4 6); \
do \
mkdir -p /mydata/elasticsearch/node-${port}/config
mkdir -p /mydata/elasticsearch/node-${port}/data
chmod -R 777 /mydata/elasticsearch/node-${port}
cat << EOF >/mydata/elasticsearch/node-${port}/config/elasticsearch.yml
cluster.name: my-es #集群的名称,同一个集群该值必须设置成相同的
node.name: es-node-${port} #该节点的名字
node.master: false #该节点有机会成为 master 节点
node.data: true #该节点可以存储数据
network.host: 0.0.0.0
#network.publish_host: 192.168.56.10 #互相通信 ip,要设置为本机可被外界访问的 ip,否则
无法通信
http.host: 0.0.0.0 #所有 http 均可访问
http.port: 920${port}
transport.tcp.port: 930${port}
#discovery.zen.minimum_master_nodes: 2 #设置这个参数来保证集群中的节点可以知道其
它 N 个有 master 资格的节点。官方推荐(N/2)+1
discovery.zen.ping_timeout: 10s #设置集群中自动发现其他节点时 ping 连接的超时时间
discovery.seed_hosts: ["172.18.12.21:9301", "172.18.12.22:9302", "172.18.12.23:9303"] #设置集群中的 Master 节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7
的新增配置
cluster.initial_master_nodes: ["172.18.12.21"] #新集群初始时的候选主节点,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \ -p 920${port}:920${port} -p 930${port}:930${port} \ --network=mynet --ip 172.18.12.2${port} \ -e ES_JAVA_OPTS="-Xms300m -Xmx300m" \ -v
/mydata/elasticsearch/node-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/ela
sticsearch.yml \ -v /mydata/elasticsearch/node-${port}/data:/usr/share/elasticsearch/data \ -v /mydata/elasticsearch/node-${port}/plugins:/usr/share/elasticsearch/plugins \ -d elasticsearch:7.4.2
done

##检查
_nodes/process?pretty 查看节点状况
_cluster/stats?pretty 查看集群状态
_cluster/health?pretty 查看集群健康状况
_cat/nodes 查看各个节点信息
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
#还可以只开放一个实例端口.其他的都用集群内访问就可以啦。
#也可以使用自定义Docker网络的方式
docker network create --driver bridge --subnet 172.21.0.0/16 --gateway 172.21.0.1 mynet
#运行容器的时候,使用 --ip --network指定网络

安装Nginx

  • 随便启动一个 nginx 实例, 只是为了复制出配置

    docker run -p 80:80 --name nginx -d nginx:1.10

  • 将容器内的配置文件拷贝到当前目录:

    • mkdir -p /idata/nginx/conf
    • docker container cp nginx:/etc/nginx/. /idata/nginx/conf
  • 创建新的 nginx; 执行以下命令
    docker run -p 80:80 --name nginx \
    -v /idata/nginx/html:/usr/share/nginx/html \
    -v /idata/nginx/logs:/var/log/nginx \
    -v /idata/nginx/conf:/etc/nginx \
    -d nginx:1.10
  • 给 nginx 的 html 下面放的所有资源可以直接访问;

安装RabbitMQ

#简单安装
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p
25672:25672 -p 15671:15671 -p 15672:15672 -v /idata/rabbitmq:/var/lib/rabbitmq rabbitmq:management

4369, 25672 (Erlang发现&集群端口)
5672, 5671 (AMQP端口)
15672 (web管理后台端口)
61613, 61614 (STOMP协议端口)
1883, 8883 (MQTT协议端口)
https://www.rabbitmq.com/networking.html
#安装RabbitMQ镜像集群
#三台机器分别运行
mkdir -p /idata/rabbitmq
vi /idata/rabbitmq/hosts
192.168.0.48 rabbit1 rabbit1
192.168.0.47 rabbit2 rabbit2
192.168.0.46 rabbit3 rabbit3

#注意修改每个-h 参数,修改为正确的hostname
docker run -d --name rabbitmq -h rabbit1 -v /idata/rabbitmq:/var/lib/rabbitmq -v /idata/rabbitmq/hosts:/etc/hosts -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 -e RABBITMQ_ERLANG_COOKIE='icodingedu' rabbitmq:management
#上面这种方式匹配主机名适用于完全分布式情况,单机模拟集群,大家觉得还有更好的方式吗?(请使用自定义网络的方式)

#RABBITMQ_ERLANG_COOKIE 节点认证作用,部署集成时 需要同步该值

#节点加入集群
#初始化第一个节点
docker exec -it rabbitmq /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
Exit

#设置集群内的其他节点
docker exec -it rabbitmq /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1 #master的ip
rabbitmqctl start_app
exit

#实现镜像集群
#进入主节点进行操作
docker exec -it rabbitmq bash
rabbitmqctl set_policy -p / ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'

可以使用 rabbitmqctl list_policies -p /;查看vhost/下面的所有policy
在cluster中任意节点启用策略,策略会自动同步到集群节点
rabbitmqctl set_policy -p / ha-all "^" '{"ha-mode":"all"}'
策略模式 all 即复制到所有节点,包含新增节点,策略正则表达式为 “^” 表示所有匹配所有队列名称。“^hello”表示只匹配名为hello开始的队列

端口映射

docker create -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name hello-mysql mysql:5.7

-p HostPort:ContainerPort | IP:HostPort:ContainerPort | HostPort:ContainerPort

  • 查看端口映射

    • docker port hello-mysql

容器互联

--link name:alias,name连接容器的名称,alias连接的别名

场景:我们无需暴露mysql的情况下,让web应用使用mysql;

docker run -d -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d --link mysql01:mysql --name tomcat tomcat:7

docker exec -it tomcat bash
cat /etc/hosts