Docker 实战2案列:Nginx 负载均衡

1. 搭建 CentOS + Nginx 容器、commit 提交、在容器主机文件互拷;

搭建 Nginx 镜像

  • 用最早的镜像 CentOS,利用交互式方式进入后安装(使用 yum 或者编译安装都是可以的)
  • 提示:有些操作在 Dockerfile 里很难把它写出来(写完整或者写的完全没有问题),所以有时候需要进入容器对里面的内容进行操作。操作完成后,因为容器是不保存内容的,一旦容器被删除了,里面的内容就没有了。所以有时候会把代码文件放在主机里面,利用 -v 参数和容器进行映射,这时候要是容器宕掉了或者误删了,就没有关系,真实数据还是保留在主机里面的。
  • 那在容器里面如果做了改动,要进行保存,操作如下
# 打开终端 1,创建临时容器
# --privileged 启动管理员权限
docker run -it --privileged --name tmp centos /usr/sbin/init

# 运行上面命令后,会卡住
# 打开终端 2,进入容器
docker exec -it tmp /bin/bash

# 安装 Nginx
rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum install nginx -y

# 设置开机启动
systemctl enable nginx

# 启动 Nginx
systemctl start nginx

# yum 默认安装,配置文件会在 /etc/ 目录下
# 因为已经对这个容器做了一些操作,所以需要保存容器,下次就不需要重新安装一遍
# 所以把这个容器作为一个新的镜像保存起来,需要用到 docker commit
# 把修改好的容器,提交成一个新的镜像
# 文档:https://docs.docker.com/engine/reference/commandline/commit/#description
# 先退出镜像
exit

# 这样就创建出一个新镜像
# 因为没有使用 Dockerfile,所以希望容器启动的时候执行一些命令,比如 usr/sbin/init 和暴露 80 端口
# 这些都是可以在 Dockerfile 里写的内容
# -c:应用 Dockfile 里的结构去创建一个 image,因为直接 commit 可能会出现问题,必须要用 Dockerfile 里的命令
# 如果有多个命令,就写多个 -c
docker commit -c 'CMD ["/usr/sbin/init"]' -c "EXPOSE 80" tmp centos:nginx

# 接下去要基于新的镜像,创建一个新的容器,然后把容器里的文件映射到主机(比如配置文件)
# 配置文件肯定是需要持久化的,不能不做任何处理的存在容器里的,因此需要拷贝
# 首先把 Nginx 配置文件从容器里拷贝出来
# docker cp:容器里的文件拷贝到主机,也可以主机文件拷贝到容器
# 参考文档:https://docs.docker.com/engine/reference/commandline/cp/
# 现在执行从容器拷贝到主机
mkdir -p /home/[用户名]/nginx/conf
docker cp tmp:/etc/nginx/nginx.conf /home/[用户名]/nginx/conf/

# 此时之前创建的 tmp 容器就可以删除了
# 创建一个新容器叫 mynginx
# 主机端口 9090 映射到 容器 80
# 主机的 nginx.conf 和容器里的对应
# 之后修改配置只需要改主机的 nginx.conf,不需要进入容器去改
# 实际操作中,尽量不要去反复操作容器,容器不是持久化的,也不可能每做一个改动就去 commit 一个新镜像
# centos:nginx 是刚才创建的镜像名
# 执行后 docker images 出现一个新镜像 mynginx
docker run --name mynginx --privileged \
-p 9090:80 -v /home/[用户名]/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-d centos:nginx

2. Docker Compose 以及启动多个 Web 容器;

# 准备工作
# 之前创建的 centos:jdk 容器,里面安装了apache 和 jdk,重复利用一下
mkdir -p /home/[用户名]/nginx/web1/
mkdir -p /home/[用户名]/nginx/web2/
docker run --name web1 -d -p 8080:80 --privileged -v /home/[用户名]/nginx/web1/:/var/www/html/ centos:jdk
docker run --name web2 -d -p 8081:80 --privileged -v /home/[用户名]/nginx/web2/:/var/www/html/ centos:jdk

# 如果 web1 容器不想要了
docker stop web1 && docker stop web1

# 总结,创建容器的话,会有很多复杂的参数,映射很多目录,很多端口,以及在实际开发中会有几十个容器
# 不可能每一个容器都去执行这么多命令(手工拷贝、一条条执行,删容器要一条条删)
# 所以需要用到编排工具 Docker Compose:https://docs.docker.com/compose/overview/
# Docker 构建工具、容器编排的工具,可以配置并启动多个容器,适合复杂业务场景(类似 js 工具 webpad)
# 需要创建一个配置文件,配置文件里写入一些相关配置和命令的参数
# 就可以一次性的把多个容器根据复杂的要求启动出来,也可以一次性的关闭和删除
# 比如现在只有一个 Dockerfile,镜像什么都没有,依然可以用 Docker Compose 来生成镜像并且启动容器
# 同时还能实现依赖管理
# 比如说之前创建的两个容器 web1 和 web2 做负载均衡用,所以创建容器之前必须有 Nginx 容器

# Docker Compose 安装:https://docs.docker.com/compose/install/
# -L:有些网站有多次跳转,加入此参数随着网站跳转而跳转
# -o:把下载内容输出到指定路径的文件
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 对下载的文件赋予可执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 查看文件版本
docker-compose -v

# 需要做一个配置,肯定要有配置文件叫 yaml
# yaml 类似于 json 或者 xml,但是格式更加简洁,使用一些缩进的方式编排
# 关于 yaml 检查的在线工具:http://www.yamllint.com
# 文档引导:https://docs.docker.com/compose/gettingstarted/#step-1-setup#step-3-define-services-in-a-compose-file
# 创建空文件夹
mkdir -p /home/[用户名]/mycompose
cd /home/[用户名]/mycompose
vim docker-compose.yml
# 写入如下内容
# services:服务,也可以认为是一些任务
# ports:如果是多个,就要写很多行
# volumes:代表映射
# version:支持的 compose 版本,最新的支持 version 3
# 还有一些参数,build(用于 Dockerfile)、command(Dockerfile 中的 CMD)
services: 
  web1: 
    container_name: web1
    image: "centos:jdk"
    ports: 
      - "8080:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web1/:/var/www/html/"
  web2: 
    container_name: web2
    image: "centos:jdk"
    ports: 
      - "8081:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web2/:/var/www/html/"
version: "3"
# 写入内容结束
# 启动:https://docs.docker.com/compose/reference/up/
# up 命令可以对之前配置文件里是所写的内容进行启动
# 配置文件里创建的两个 service 全部启动,也可以指定单独的 service 启动
docker-compose up -d 

# 只停止一个容器
docker-compose stop web1

# 删除容器
docker-compose rm web1

3. Docker network、容器网络、容器间互相访问;

目标:三个容器,一个 Nginx 两个 Web,通过容器和容器之间完成负载均衡

  • 如果把 Nginx 放到主机上,就非常简单了,主机和容器之间有端口映射,只要在 Nginx 里做一个配置,立马就可以完成
  • 如果 Nginx 本身也在一个容器里面,就涉及到容器和容器之间的访问(如何互相访问,IP 是什么)

一个 Nginx,两个 Web 启动的 Docker compose 配置文件

# 配置文件
services: 
  nginx: 
    container_name: mynginx
    image: "centos:nginx"
    ports: 
      - "9090:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/conf/nginx.conf:/etc/nginx/nginx.conf"
  web1: 
    container_name: web1
    image: "centos:jdk"
    ports: 
      - "8080:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web1/:/var/www/html/"
  web2: 
    container_name: web2
    image: "centos:jdk"
    ports: 
      - "8081:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web2/:/var/www/html/"
version: "3"

# 后台启动三个容器
docker-compose up -d

容器之间通过 IP 方式互相访问(docker network 网络设置)

# 查看网络
docker network ls
# 返回
NETWORK ID          NAME                DRIVER              SCOPE
ab368b5af331        bridge              bridge              local
1f23995f905a        host                host                local
5c34a7a8f019        none                null                local
# bridge:创建并启动一个容器,如果没有设置并且指定网络名称,则会自动加入 bridge(桥接模式)
# 一般会使用 bridge 模式做主机和容器之间的互通
# host:一般不会使用 host 模式,影响了 docker 的隔离机制,不是很安全
# none:就是没有网络
# * 如果不指定任何的网络,会创建以“文件夹名”加上“_default”的网络,是一个桥接网络

# 检查 network
docker network inspect bridge
# IPAM.Config:包含子网和网关
# Containers.Name/EndpointID/MacAddress/IPv4Address/IPv6Address:当启动了容器之后
# 会有容器加入 Containers 里,配置文件就是这么写的
# 它自动分配了 IP 地址(IPv4)
# 找一个容器,交互式进入一下
docker exec -it mynginx /bin/bash
# 把容器里默认是没有 ifconfig 的,可以安装,也可以如下操作,查看 IP
cat /etc/hosts
# ping 其它容器的 IP
ping 172.17.0.4
# 访问其它容器(容器之间通过 IP 互通)
# IP 的分配依赖默认的桥接模式,创建一个虚拟的网络地址
curl http://172.19.0.4

# 之前通过 docker-compose 启动了三个容器,如果没有做任何设置
# docker network ls 会自动出现 NAME 为 mycompose_default
# 这个部分也是可以自定义的,当创建并启动的时候,会自己创建一个网络
# 如果通过单独的命令,去启动创建一个网络,并且设置子网,产生一些 IP

# 首先创建网络,参考:https://docs.docker.com/engine/reference/commandline/network_create/
docker network create -d bridge mynginx
# 再启动容器,这时创建的容器会加入“mynginx”这个网络
docker run -d --network=mynginx

# docker network create 创建的网络由于没有加参数,所以没有什么意义
# 一般来说需要去指定,比如子网
# 子网掩码的计算地址:http://tool.chinaz.com/Tools/subnetmask
# 设置子网地址
docker network create -d bridge --subnet=192.128.0.0/16 mynginx
# 查看网络列表
docker network ls
# 列出刚才创建的网络
NETWORK ID          NAME                DRIVER              SCOPE
d9fc9ab2d628        mynginx             bridge              local
...
# 查看指定网络
docker network inspect mynginx
# 返回 IPAM.Config.Subnet 为 192.128.0.0/16
# Containers 为空,因为当前没有任何容器加入到这个网络

# 修改 Compose 配置,让三个容器全部加入到新的网络中
# 参考链接:https://docs.docker.com/compose/compose-file/#network-configuration-reference
# 如何对 Compose 的配置文件设置基本网络
cd /home/[用户名]/mycompose
vim docker-compose.yml
# 修改配置文件(根部加入 networks,三个 service 分别加入 networks,一个容器可以加入若干网络)
# 注意 mynginx 和 mynginx 一致
# mynginx-net 和 mynginx-net 一致(外部网络名称)
networks: 
  mynginx-net: 
    external: 
      name: mynginx
services: 
  nginx: 
    container_name: mynginx
    image: "centos:nginx"
    networks: 
      - mynginx-net
    ports: 
      - "9090:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/conf/nginx.conf:/etc/nginx/nginx.conf"
  web1: 
    container_name: web1
    image: "centos:jdk"
    networks: 
      - mynginx-net
    ports: 
      - "8080:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web1/:/var/www/html/"
  web2: 
    container_name: web2
    image: "centos:jdk"
    networks: 
      - mynginx-net
    ports: 
      - "8081:80"
    privileged: true
    volumes: 
      - "/home/hua/nginx/web2/:/var/www/html/"
version: "3"
# 保存
# 之前三个容器(mynginx、web1、web2)被停掉了
# 由于使用的是外部容器,不需要使用 up 命令重新删、创建、启动容器
# 直接使用 start
docker-compose start

# 查看网络
# Ccontainers 会出现三个容器,IPv4Address 加入了之前创建的网络
docker network inspect mynginx

# 进入容器(容器名称和网络名称一样)
docker exec -it mynginx /bin/bash
cat /etc/hosts

4. (案例)Docker compose 创建网络、指定容器 IP、启动简单 Nginx 负载均衡;

目标

  • 在 compose up 的时候或者启动容器的时候自动创建网络、而不需要在外部手动创建。在实战的时候、外部额外的操作越少越好。最好是一到两个文件、一条命令直接启动
  • 容器 IP:在容器创建好之后,指定 IP。因为在做负载均衡、或者做一些需要和 IP 地址有关系的程序的调用,一定需要 IP 的参照(随机创建 IP 不好控制)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值