3.docker网络及主从构建

1. lnrp 环境构建
1.1. 构建镜像
nginx dockerfile
FROM centos:centos7
RUN mkdir /data && mkdir /conf
RUN groupadd -r nginx && useradd -r -g nginx nginx
#修改时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ARG PHP_VERSION=7.2
#添加centos源(先下载wget)
COPY ./epel-7.repo /etc/yum.repos.d/epel.repo
#COPY
#RUN yum install -y wget
#RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum update -y \
&& yum clean all \
&& yum makecache \
&& yum -y install gcc gcc-c++ autoconf automake make zlib zlib-devel net-tools openssl* pcre* wget \
&& yum clean all && rm -rf /var/cache/yum/*
#声明匿名卷
VOLUME /data
COPY ./nginx-1.14.1.tar.gz /data/nginx-1.14.1.tar.gz
RUN cd /data \
&& tar -zxvf nginx-1.14.1.tar.gz \
&& cd nginx-1.14.1 \
&& ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
&& make && make install && rm -rf /data/nginx-1.14.1.tar.gz && rm -rf /data/nginx-1.14.
COPY ./conf/nginx.conf /conf
#全局使用nginx,软链接
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin
#进入容器时默认打开的目录
WORKDIR /conf
#声明端口
EXPOSE 80
#容器启动的时候执行,在docker run过程当中是会被其他指令替代
#CMD ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
#执行一条指
# ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
php dockerfile
FROM php:7.3-fpm-alpine
# Version
ENV PHPREDIS_VERSION 4.0.0
# Libs
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add \
curl \
vim \
wget \
git \
openssl-dev\
zip \
unzip \
g++ make autoconf
# docker方式安装PDO extension # 安装扩展
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& docker-php-ext-install pdo_mysql \
&& docker-php-ext-install pcntl \
&& docker-php-ext-install sysvmsg
# Redis extension
RUN wget http://pecl.php.net/get/redis-${PHPREDIS_VERSION}.tgz -O /tmp/redis.tar.tgz \
&& pecl install /tmp/redis.tar.tgz \
&& rm -rf /tmp/redis.tar.tgz \
&& docker-php-ext-enable redis
# 修改php.ini的文件 extension=redis.so
EXPOSE 9000
#设置工作目录
WORKDIR /www
redis的 dockerfile
FROM centos:centos7
RUN groupadd -r redis && useradd -r -g redis redis
RUN mkdir data ;\
yum update -y ; \
yum -y install gcc automake autoconf libtool make wget epel-release gcc-c++;
COPY ./redis-5.0.7.tar.gz redis-5.0.7.tar.gz
RUN mkdir -p /usr/src/redis; \
tar -zxvf redis-5.0.7.tar.gz -C /usr/src/redis; \
rm -rf redis-5.0.7.tar.gz; \
cd /usr/src/redis/redis-5.0.7 && make ; \
cd /usr/src/redis/redis-5.0.7 && make install
COPY ./conf/redis.conf /usr/src/redis/redis-5.0.7/redis.conf
EXPOSE 6379
ENTRYPOINT ["redis-server", "/usr/src/redis/redis-5.0.7/redis.conf"]
或者直接 docker pull redis:6.0-rc-alpine
构建镜像
docker build -t php7 .
docker build -t nginx1.4 .
docker build -t redis5 .
保存容器数据卷
  mkdir docker
  mkdir docker/images
  mkdir docker/images/data/
  mkdir docker/images/data/php
  mkdir docker/images/data/nginx
  mkdir docker/images/data/redis
  mkdir docker/images/data/php/www
  mkdir docker/images/data/nginx/conf
添加config.conf文件到docker/images/data/nginx/conf目录
user  root;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    sendfile        on;
    keepalive_timeout  65;
    server {
            listen       80;
            access_log  /usr/local/nginx/logs/$host  main;
            location / {
                root  /www; #php容器的目录
                default_type text/html;
            }
            location  ~ \.php/?.*  {
                    default_type text/html;
                    #做php-fpm 配置,注意地址
                    root           /www;  #php-fpm容器当中的路径,不是nginx容器路径
                    fastcgi_index  index.php;

                    fastcgi_pass   192.168.200.140:9001; #php容器端口

                    #为php-fpm指定的根目录
                    fastcgi_param  SCRIPT_FILENAME  $DOCUMENT_ROOT$fastcgi_script_name;
                    #注意是容器当中的位置

                    #定义变量 $path_info ,用于存放pathinfo信息
                    set $path_info "";
                    if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
                            #将文件地址赋值给变量 $real_script_name
                            set $real_script_name $1;
                                #将文件地址后的参数赋值给变量 $path_info
                            set $path_info $2;
                        }
                         #配置fastcgi的一些参数
                        fastcgi_param SCRIPT_NAME $real_script_name;
                        fastcgi_param PATH_INFO $path_info;
                        include        /usr/local/nginx/conf/fastcgi_params;
                 }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                  root   html;
            }
        }
}

 

添加index.php文件到docker/images/data/php/www目录
<?php
$redis = new Redis();
$redis->connect('192.168.169.140', 6379);//serverip port
$redis ->set("test" , "Hello World");
echo $redis ->get("test");
 

构建容器

docker run -itd -v /docker/images/data/nginx/conf:/conf -p 81:80 --name nginx1.4 nginx1.4
docker run -itd -v /docker/images/data/php/www:/www -p 9001:9000 --name php-fpm-7 php7
docker run -itd -p 6379:6379 --name redis5 redis5
验证
关闭防火墙 systemctl stop firewalld
在浏览器中输入192.168.200.140:81/index.php 返回Hello World
 
3. redis 基础内容
3.1 redis 介绍
redis 是 一 个 key-value 存 储 系 统 。 它 支 持 存 储 的 value 类型相对更多,包括 string( 字符串 ) list( 链 表 ) set( 集合 ) zset(sorted set -- 有序集合 ) hash (哈希类型)。这些数据类型都支持 push/pop add/remove
取交集并集和差集及更丰富的操作, 而且这些操作都是原子性的。在此基础上, redis 支持 各种不同方式的排序。为了保证效率,数据都是缓存在 内存中
1. 为什么会出现 redis 呢?
对于网页来说数据来自于数据库,而数据库实际上是存在这性能的瓶颈(一般单表早期的瓶颈就在 2000w --[ 索引的优化效率瓶颈 ]
即时是做了主从以及集群架构也依然还是会有速率的问题,因此这个时候以内存暂时存储数据的想法就横空出世了;产品也很多,不去探讨重点讲解 redis
2. redis 特性
2.1 速度快
正常情况下, Redis 执行命令的速度非常快,官方给出的数字是读写性能可以达到 10 / 秒,当然这也取决于机器的性能,但这里先不讨论机器性能上的差异,只分析一下是什么造就了 Redis 除此之快的速度,可以大致归
纳为以下四点 :
1. Redis 的所有数据都是存放在内存中的,,所以把数据放在内存中是 Redis 速度快的最主要原因。
2. Redis 是用 C 语言实现的,一般来说 C 语言实现的程序 距离 操作系统更近,执行速度相对会更快。
3. Redis 使用了单线程架构,预防了多线程可能产生的竞争问题。
4. 作者对于 Redis 源代码可以说是精打细磨,曾经有人评价 Redis 是少有的集性能和优雅于一身的开源代码。
2.2 基于 key-value
几乎所有的编程语言都提供了类似字典的功能,例如 Java 里的 map Python 里的 dict, 类似于这种组织数据的方式叫作基于键值的方式,与很多键值对数据库不同的是, Redis 中的值不仅可以是字符串,而且还可以是具
体的数据结构,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。 Redis 的全称是 REmote Dictionary Server, 它主要提供了 5 种数据结构 : 字符串、哈希、列表、集合、有序集合,同时在字符串的基础之上
演变出了位图 ( Bitmaps) HyperLogLog 两种神奇的 数据结构 ,并且随着 LBS ( Location BasedService, 基于位置服务 ) 的不断发展, Redis 3.2 版本中加人有关 GEO ( 地理信息定位 ) 的功能,总之在这些数据结构的帮助下,
开发者可以开发出各种 有意思 的应用。
2.3. 丰富的功能
除了 5 种数据结构, Redis 还提供了许多额外的功能 :
1. 提供了键过期功能,可以用来实现缓存。
2. 供了发布订阅功能,可以用来实现消息系统。
3. 支持 Lua 脚本功能,可以利用 Lua 创造出新的 Redis 命令。
4. 提供了简单的事务功能,能在一定程度 上保证事务特性。
5. 提供了流水线 ( Pipeline) 功能,这样客户端能将 - 批命令 - 一次性传到 Redis, 减少网络的开销。
2.4. 简单稳定 2.5. 支持的语言多 2.6. 持久化 2.7. 主从复制
 
3. redis 应用场景
3.1. 缓存
缓存机制几乎在所有的大型网站都有使用,合理地使用缓存不仅可以加快数据的访问速 座而且能够有效地降低后端数据源的压力。 Redis 提供了键值过期时间设置,并且也提供 7 灵活控制最大内存和内存溢出后的淘汰
策略。可以这么说,一个合理的缓存设计能够为一 个网站的稳定保驾护航。第 11 章将对缓存的设计与使用进行详细说明。
3.2. 排行榜系统
排行榜系统几乎存在于所有的网站,例如按照热度排名的排行榜,按照发布时间的排行榜,按照各种复杂维度计算出的排行榜, Redis 提供了列表和有序集合数据结构,合理地使用这些数据结构可以很方便地构建各种
排行榜系统。
3.3. 计数器
计数器在网站中的作用至关重要,例如视频网站有播放数、电商网站有浏览数,为了保证数据的实时性,每一次播放和浏览都要做加 1 的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。 Redis 天然支持计
数功能而且计数的性能也非常好,可以说是计数器系统的重要选择。
3.4. 社交网站
/ 踩、粉丝、共同好友 / 喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常 比较大,而且传统的关系型数据不太适 合保存这种类型的数据, Redis 提供的数据结构可以相对比较容易地实现这些
功能。
3.5. 消息队列
消息队列系统可以说是一 - 个大型网站的必备基础组件,因为其具有业务解耦、非实时业务削峰等特性。 Redis 提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不够足够强大,但是对于般的消息队列
功能基本可以满足。
3.2 redis 基础数据类型及场景运用
3.2.1 字符
字符串是 redis 最基础的数据结构。首先键都是字符串类型,而且其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种类型结构的学习奠定基础。
1. 命令
-- 设置参数:
set key value
setnx key value
set key value xx
mset key value [key value ...]
-- 获取参数
get key
get key [key ...]
-- 计数
incr key
decr key
-- 是否存在
exists key
2. 场景
1. 缓存功能
如下图是比较典型的缓存使用场景,其中 redis 作为缓存层, mysql 作为存储层大部分请求的数据都是从 redis 中获取。由于 redis 具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用
2. 计数
许多应用都会使用 redis 作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他数据源。比如视频播放一次就自动加 1
3. 共享 session
4. 限速
很多应用处于安全的考虑,会在每次进行登入的时候,设置短信验证登入;而对于短信接口不被频繁访问,会限制用户每分钟获取验证码的频率,比如一份中不超过 5
当然也可以设置 ip 地址不能在 1s 之间内访问超过 n
 
3.2.2 哈希
哈希类型是指键值本身又是一个键值对结构(就是多维数组), value={{field, value},...{fieldN, valueN}}
1. 命令
-- 设置
hset set field value
如: hset user:1 name shineyork
-- 获取
hget key field
如: hget user:1 name
-- 判断是否存在
hkeys key
2. 场景
典型场景就是记录用信息
3.2.3 列表
列表类型是用来存储多个有序的字符串,如图 a,b,c,d,e 从左到右组成一个有序的列表,列表中的每个字符串称为元素。在 redis 中,可以对列表两端插入 (push) 和弹出 (pop) ,还可以指定范围的元素列表,获取指定索引下
表的元素等。列表是种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。
1. 命令
-- 从右边插入元素
rpush key value [value ...]
-- 实例
> rpush listkey c b a
> lrange listkey 0 -1
-- 从左边插入元素
lpush key value [value ...]
-- 获取列表指定索引下标元素
lindex key index
-- 获取列表长度
llen key
-- 删除
-- 从左侧弹出元素
lpop key
-- 从右侧弹出元素
rpop key
2. 使用场景
1. 消息队列
Redis lpush+brpop 命令组合即可实现阻塞队列,生产者客户端使用 lrpush 从列表左侧插入元素,多个消费者客户端使用 brpop 命令阻塞式的 列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性
2. 文章列表
每个用户有属于自己的文章列表,先需要分页展示文章列表。此时可以考虑使用列表因为列表不但是有序的,同时支持按照索引范围获取元素。
3.2.4 集合
集合 (set) 类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取原生。集合 user:1:name 包含
“peter” “shineyork” “cara” “will” 四个元素。
1. 命令
-- 添加元素
sadd key element [element ...]
-- 实例
> exists myset
> sadd myset a b c
(integer)
> sadd myset a b
0
-- 删除元素
srem key element [element ...]
-- 从集合随机弹出元素
spop key
-- 获取所有元素
smembers key
2. 使用场景
集合类型比较典型的使用场景是标签 (tag) 。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共
同喜欢的标签,这些数据对于用户体验以及增强用户黏合度比较重要
下面使用集合类型实现标签功能的若干功能。
(1) 给用户添加标签
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag1 tag2 tag3
...
sadd user:k:tags tag1 tag2 tag3
(2) 给标签添加用户
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
3.2.5 有序集合
有序集合相对哈希、列表、集合来说会有点点陌生, 但既然叫有序集合,那么它和集合必然有着联系,它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下标作为
排序依据不同的是,它给每个元素设置 - 个分数 (score) 作为排序的依据。
1. 命令
-- 添加成员
zadd key score member [score member ...]
-- 实例
> zadd user:name 300 php
(integer)1
> zadd user:name 1 .net 20 c++ 90 java 200 python
-- 计算排名
zrank key member
zrevrank key member
-- 删除成员
zrem key member [member ...]
2. 使用场景
有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多个方面的:按照实际、按照播放数量、按照获得的赞数。比如以赞数这个维度,记录每天用户上传视
频的排行榜。
(1) 添加用户赞数
例如用户 mike 上传了一个视频,并获得了 3 个赞,可以使用有集合的 zadd zincrby 功能:
zadd user:info:20200428 3 mike
如果之后再获得一个赞,可以使用 zincrby
(2) 取消用户赞数
由于各种原因 ( 例如用户注销、用户作弊需要将用户删除,此时需要讲用户从榜单删除掉,可以使用 zrem
zrem user:info:20200428 mike
(3) 展示获取赞数最多的是个用户
此功能使用 zrevrange 命令实现:
zrevrangebyrank user:info:20200428 0 9
(4) 展示用户信息以及用户分数
此功能将用户名作为键后缀,讲用户信息保存在哈希类型中,至于用户的分数和排名可以使用 zscore zrank 两个功能:
zscore user:info:20200428 mike
zrank user:info:20200428 mike
4. docker 网络模式
docker 安装后,默认会创建下面三种网络类型 
1. bridge :桥接网络
默认情况下启动的 Docker 容器,都是使用 bridge Docker 安装时创建的桥接网络,每次 Docker 容器重启时,会按照顺序获取对应的 IP 地址,这个就导致重启下, Docker IP 地址就变
2. none
无指定网络 使用 --network=none docker 容器就不会分配局域网的 IP
3. host
主机网络 使用 --network=host ,此时, Docker 容器的网络会附属在主机上,两者是互通的。 例如,在容器中运行一个 Web 服务,监听 8080 端口,则主 机的 8080 端口就会自动映射到容器中
弊端:
1 )最明显的就是容器不再拥有隔离、独立的网络栈。容器会与宿主机竞争网络栈的使用,并且容器的崩溃就可能导致宿主机崩溃,在生产环境中,这种 问题可能是不被允许的。
2 )容器内部将不再拥有所有的端口资源,因为一些端口已经被宿主机服务、 bridge 模式的容器端口绑定等其他服务占用掉了
4. 指定自定义网络
因为默认的网络不能制定固定的地址,所以我们将创建自定义网络,并指定网段: 192.168.1.0/24 并命名为 mynetwork ,指令
如下:
~ docker network create --subnet=192.160.1.0/24 mynetwork
~ docker run -itd --network=redis-network --ip 192.168.1.10 --name dockerName imagesName
~ docker network ls
~ docker network rm mynetwork
!注意:这个网络段不要和宿主机的网络端冲突,不然会容易对宿主机产生影响
5. redis 主从主从复制
5.1. 什么是主从复制
主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为主节点 (master) ,后者称为从节点 (slave), 数据的复制是单向的,只能由主节点到 从节点。
默认情况下,每台 Redis 服务器都是主节点,且一个主节点可以有多个从节点 ( 或没有从节点 ) ,但一个从节点只能有一个主节点。
5.2. 实践主从复制
dockerfile
FROM alpine:3.11
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add gcc g++ libc-dev wget vim openssl-dev make linux-headers \
&& rm -rf /var/cache/apk/*
COPY ./redis-5.0.7.tar.gz redis-5.0.7.tar.gz
# 通过选择更小的镜像,删除不必要文件清理不必要的安装缓存,从而瘦身镜像
# 创建相关目录能够看到日志信息跟数据跟配置文件
RUN mkdir -p /usr/src/redis \
&& mkdir -p /redis/data \
&& mkdir -p /redis/conf \
&& mkdir -p /redis/log \
&& mkdir -p /var/log/redis \
&& tar -zxvf redis-5.0.7.tar.gz -C /usr/src/redis \
&& rm -rf redis-5.0.7.tar.gz \
&& cd /usr/src/redis/redis-5.0.7 && make \
&& cd /usr/src/redis/redis-5.0.7 && make install;
EXPOSE 6379
# CMD ["redis-server"]
构建容器
docker network create --subnet=192.160.1.0/24 redis5sm
docker run -itd -v /redis_2004/masterandslave/master:/redis -p 6350:6379 --network=redis5sm --ip=192.160.1.150 --name redis5master redis5asm
docker run -itd -v /redis_2004/masterandslave/slave:/redis -p 6340:6379 --network=redis5sm --ip=192.160.1.140 --name redis5slave redis5asm
3. 配置主从
这里通过命令构建
1. 确保主服务器的 redis-master 的配置是 ok
# bind 127.0.0.1
protected-mode no
2. 进入从服务器
执行如下命令
SLAVEOF 192.160.1.150 6379
配置即可
 
常见问题
操作:
docker network create --subnet=192.160.1.0/24 redis5sm
docker run -itd -v /redis_2004/masterandslave/master:/redis -p 6350:6379 --network=redis5sm --ip=192.160.1.150 --name redis5master redis5asm
docker run -itd -v /redis_2004/masterandslave/slave:/redis -p 6340:6379 --network=redis5sm --ip=192.160.1.140 --name redis5slave redis5asm

从redis:
slaveof 192.160.1.150 6350
127.0.0.1:6379> info replication
master_link_status:down

问题:
1.master_link_status是down,且主redis添加一个值从redis没有

2.我用redis客户端在本地连接直接连接不上

3.自定网络的ip是可以随意的吗 比如我主机是192.168.200.130 docker可以直接定义成192.160.1.150

解决方法
1.master_link_status是down,且主redis添加一个值从redis没有 这个是因为你的从机找不到主机

原因:
a. 你的主机配置问题
b. 你的从机地址填错了
c.  网络不通,建议ping一下看看

2.我用redis客户端在本地连接直接连接不上
原因:
a.服务没有开启
b.端口开放的问题;宿主机和容器的端口
3.自定网络的ip是可以随意的吗  : 可以
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值