(1)使用Docker-compose实现Tomcat+Nginx负载均衡
概念
正向代理:客户端想要访问一个服务器,但是它可能无法直接访问这台服务器,这时候这可找一台可以访问目标服务器的另外一台服务器,而这台服务器就被当做是代理人的角色 ,称之为代理服务器,于是客户端把请求发给代理服务器,由代理服务器获得目标服务器的数据并返回给客户端。客户端是清楚目标服务器的地址的,而目标服务器是不清楚来自客户端,它只知道来自哪个代理服务器,所以正向代理可以屏蔽或隐藏客户端的信息。
反向代理:从上面的正向代理,你会大概知道代理服务器是为客户端作代理人,它是站在客户端这边的。其实反向代理就是代理服务器为服务器作代理人,站在服务器这边,它就是对外屏蔽了服务器的信息,常用的场景就是多台服务器分布式部署,像一些大的网站,由于访问人数很多,就需要多台服务器来解决人数多的问题,这时这些服务器就由一个反向代理服务器来代理,客户端发来请求,先由反向代理服务器,然后按一定的规则分发到明确的服务器,而客户端不知道是哪台服务器。常常用nginx来作反向代理。
Nginx的负载均衡:
负载:就是Nginx接受请求
均衡:Nginx将收到的请求按照一定的规则分发到不同的服务器进行处理
nginx代理tomcat集群,代理2个以上tomcat;
创建项目的目录结构如下:
即代理三个tomcat
编写nginx的默认配置文件
通过upstream tomcats配置后面负载均衡的策略选择
先使用的是轮询算法(默认),配置内容如下
upstream tomcats {
server c_tc1:8080;
server c_tc2:8080;
server c_tc3:8080;
}
server {
listen 2419;
server_name localhost;
location / {
proxy_pass http://tomcats; # 请求转向tomcats
}
}
docker-compose.yml
version: "3.8"
services:
nginx:
image: nginx
container_name: c_ngx
ports:
- 80:2419
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf # 挂载配置文件
depends_on:
- tomcat01
- tomcat02
- tomcat03
tomcat01:
image: tomcat
container_name: c_tc1
volumes:
- ./tomcat01:/usr/local/tomcat/webapps/ROOT # 挂载web目录
tomcat02:
image: tomcat
container_name: c_tc2
volumes:
- ./tomcat02:/usr/local/tomcat/webapps/ROOT
tomcat03:
image: tomcat
container_name: c_tc3
volumes:
- ./tomcat03:/usr/local/tomcat/webapps/ROOT
index.html
I am the host 03/02/01
了解nginx的负载均衡策略,并至少实现nginx的2种负载均衡策略
常用的负载均衡策略有
- 轮询(默认)
- 指定权重
- IP绑定 ip_hash
- fair(第三方)
- url_hash(第三方)
这里选择测试默认的轮询算法和指定权重算法
轮询算法
nginx的配置文件上面已经给出
cd homework4/
sudo docker-compose up -d --build
成功运行yml文件,由于之前已经创建完成,结果如下
于是可以通过浏览器访问localhost发现是可以成功访问之前设置的index.html界面的,并且刷新界面结果会轮询。这里为了直观看出负载均衡的策略,直接用创建py文件测试
test_lx.py
import requests
url = 'http://localhost'
for i in range(1,10):
response=requests.get(url)
print(response.text)
得到结果如下,可发现是三个tomcat服务器是轮流执行的
权重算法
更改default.conf文件
upstream tomcats {
server c_tc1:8080 weight=1; //weight后面的数字表示权重
server c_tc2:8080 weight=3;
server c_tc3:8080 weight=5;
}
server {
listen 2419;
server_name localhost;
location / {
proxy_pass http://tomcats; # 请求转向tomcats
}
}
重新sudo docker-compose up -d --build
直接使用py代码测试
test.qz.py
import requests
url = 'http://localhost'
count={'I am the host 03':0,'I am the host 01':0,'I am the host 02':0}
for i in range(0,90):
response=requests.get(url)
if 'I am the host 03' in response.text:
count['I am the host 03'] += 1
if 'I am the host 02' in response.text:
count['I am the host 02'] += 1
if 'I am the host 01' in response.text:
count['I am the host 01'] += 1
print(response.text)
print(count)
显然三种结果的出现比例和权重是一致的
(2) 使用Docker-compose部署javaweb运行环境
- 分别构建tomcat、数据库等镜像服务;
- 成功部署Javaweb程序,包含简单的数据库操作;
- 为上述环境添加nginx反向代理服务,实现负载均衡。
创建项目文件,文件结构如图(javaweb程序老师给的参考博客)
其中war包放在webapp文件目录下
文件配置
docker-compose.yml
version: "3"
services:
tomcat00:
image: tomcat
hostname: hostname
container_name: tomcat00
ports:
- "5050:8080" #后面访问网页的时候要选择对应的端口号5050
volumes: #数据卷
- "./webapps:/usr/local/tomcat/webapps"
- ./wait-for-it.sh:/wait-for-it.sh
networks: #网络设置静态IP
webnet:
ipv4_address: 15.22.0.15
mymysql: #mymysql服务
build: . #通过MySQL的Dockerfile文件构建MySQL
image: mymysql:test
container_name: mymysql
ports:
- "3309:3306"
command: [
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_unicode_ci'
]
environment:
MYSQL_ROOT_PASSWORD: "123456"
networks:
webnet:
ipv4_address: 15.22.0.6
nginx:
image: nginx
container_name: "nginx-tomcat"
ports:
- 8080:8080
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf # 挂载配置文件
tty: true
stdin_open: true
networks:
webnet:
ipv4_address: 15.22.0.7
networks: #网络设置
webnet:
driver: bridge #网桥模式
ipam:
config:
-
subnet: 15.22.0.0/24 #子网
default.conf
upstream tomcats {
server tomcat00:5050;
}
server {
listen 8080
server_name localhost;
location / {
proxy_pass http://tomcat123;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
docker-entrypoint.sh
#!/bin/bash
mysql -uroot -p123456 << EOF
source /usr/local/grogshop.sql;
dockerfile
# 这个是构建MySQL的dockerfile
FROM registry.saas.hand-china.com/tools/mysql:5.7.17
# mysql的工作位置
ENV WORK_PATH /usr/local/
# 定义会被容器自动执行的目录
ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d
#复制gropshop.sql到/usr/local
COPY grogshop.sql /usr/local/
#把要执行的shell文件放到/docker-entrypoint-initdb.d/目录下,容器会自动执行这个shell
COPY docker-entrypoint.sh $AUTO_RUN_DIR/
#给执行文件增加可执行权限
RUN chmod a+x $AUTO_RUN_DIR/docker-entrypoint.sh
# 设置容器启动时执行的命令
#CMD ["sh", "/docker-entrypoint-initdb.d/import.sh"]
修改连接数据库的IP
通过ip config -a查看本机ip地址,inet对应的即为结果
修改jdbc.properties对应的ip地址和之前设置的对应端口号
启动容器
docker-compose up -d --build
数据库操作
访问网页,登陆
http://127.0.0.1:5050/ssmgrogshop_war
对应的可以进行数据库操作
修改nginx配置文件,反向代理tomcat
upstream tomcats {
server tomcat00:5050;
server tomcat00:5051;
server tomcat00:5052;
}
修改yml文件,增加
tomcat01:
image: tomcat
hostname: hostname
container_name: tomcat01
ports:
- "5051:8080" #后面访问网页的时候要选择对应的端口号5050
volumes: #数据卷
- "./webapps:/usr/local/tomcat/webapps"
- ./wait-for-it.sh:/wait-for-it.sh
networks: #网络设置静态IP
webnet:
ipv4_address: 15.22.0.16
tomcat02:
image: tomcat
hostname: hostname
container_name: tomcat02
ports:
- "5052:8080" #后面访问网页的时候要选择对应的端口号5050
volumes: #数据卷
- "./webapps:/usr/local/tomcat/webapps"
- ./wait-for-it.sh:/wait-for-it.sh
networks: #网络设置静态IP
webnet:
ipv4_address: 15.22.0.17
nginx:
depends_on:
- tomcat00
- tomcat01
- tomcat02
重新运行容器,可以发现在三个端口下都可以访问nginx
(3)使用Docker搭建大数据集群环境
环境搭建
- 拉取ubantu镜像
sudo su
docker pull ubantu
- 创建dockerfile文件
FROM ubuntu
maintainer Yaobink
- 进入ubantu容器
docker build -t ubuntu .
docker run -it --name ubuntu ubuntu
Ubuntu系统初始化
- 更新系统软件源
更新系统源命令如下:
apt-get update
- 安装vim
apt-get install vim
- 安装sshd
接着安装sshd,因为在开启分布式Hadoop时,需要用到ssh连接slave:
apt-get install ssh
然后运行如下脚本即可开启sshd服务器:
/etc/init.d/ssh start
但是这样的话,就需要每次在开启镜像时,都需要手动开启sshd服务,因此我们把这启动命令写进~/.bashrc文件,这样我们每次登录Ubuntu系统时,都能自动启动sshd服务;
vim ~/.bashrc
在该文件中最后一行添加如下内容:
/etc/init.d/ssh start
配置sshd
安装好sshd之后,我们需要配置ssh无密码连接本地sshd服务,如下命令:
ssh-keygen -t rsa #一直按回车键即可
cat id_rsa.pub >> authorized_keys
执行完上述命令之后,即可无密码访问本地sshd服务;
安装JDK
- 根据官方文档,最好下载java8
apt install openjdk-8-jdk
- 安装好后需要配置环境变量
vim ~/.bashrc #打开配置文件
#在最后添加使~/.bashrc生效
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
export PATH=$PATH:$JAVA_HOME/bin
source ~/.bashrc
存档
docker commit 09ab62943c02 ubuntu/jdk8
docker run -it -v /home/y/hw4_3/build:/root/build --name ubuntu-jdk8 ubuntu/jdk8
安装Hadoop
首先下载好Hadoop,这里下载的是3.2.1的版本,移入ubuntu桌面
然后通过cp复制到挂载的文件目录下,解压文件,并验证安装
sudo cp /home/y/桌面/hadoop-3.2.1.tar.gz /home/y/hw4_3/build
tar -zxvf hadoop-3.2.1.tar.gz -C /usr/local
cd /usr/local/hadoop-3.2.1
./bin/hadoop version
配置Hadoop集群
- 进入配置文件存放目录:
cd /usr/local/hadoop-3.2.1/etc/hadoop
- 修改环境变量
vim hadoop-env.sh
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
- 修改core-site.xml
vim core-site.xml
添加:
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
</configuration>
- 修改hdfs-site.xml
vim hdfs-site.xml
添加:
<configuration>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/namenode_dir</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/datanode_dir</value>
</property>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
</configuration>
- 修改mapred-site.xml
vim mapred-site.xml
添加:
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.2.1</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.2.1</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.2.1</value>
</property>
</configuration>
- 修改yarn-site.xml
vim yarn-site.xml
添加:
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
</configuration>
修改脚本
- 进入脚本文件存放目录:
cd /usr/local/hadoop-3.2.1/sbin
对于start-dfs.sh和stop-dfs.sh文件,添加下列参数:
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
对于start-yarn.sh和stop-yarn.sh,添加下列参数:
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
- 存档
sudo docker commit ID ubuntu/hadoop
运行Hadoop集群
- 在三个终端上开启三个容器运行ubuntu/hadoop镜像,分别表示Hadoop集群中的master,slave01和slave02;
# 第一个终端
docker run -it -h master --name master ubuntu/hadoop
# 第二个终端
docker run -it -h slave01 --name slave01 ubuntu/hadoop
# 第三个终端
docker run -it -h slave02 --name slave02 ubuntu/hadoop
- 修改/etc/hosts
vim /etc/hosts
#修改为
172.17.0.2 master
172.17.0.3 slave01
172.17.0.4 slave02
- 测试ssh
检测下是否master是否可以连上slave01和slave02(exit为退出)
ssh slave01
ssh slave02
- 修改workers
vim /usr/local/hadoop-3.2.1/etc/hadoop/workers
# 将localhost替换成两个slave的主机名
slave01
slave02
启动集群
在master终端上运行如下命令
cd /usr/local/hadoop-3.2.1
bin/hdfs namenode -format # 格式化文件系统
sbin/start-dfs.sh # 开启NameNode和DataNode服务
bin/hdfs dfs -mkdir /user # 建立HDFS文件夹,也可以放到下面示例程序中进行
bin/hdfs dfs -mkdir /user/root
bin/hdfs dfs -mkdir input
bin/hdfs dfs -put etc/hadoop/*.xml input # 将xml复制到input下,作为示例程序输入
sbin/start-yarn.sh # 开启ResourceManager和NodeManager服务
jps # 查看服务状态
运行Hadoop示例程序
在master终端运行:
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar grep input output 'dfs[a-z.]+' # 运行示例
bin/hdfs dfs -get output output # 获取输出结果
cat output/* # 查看输出结果
sbin/stop-all.sh # 停止所有服务
查看文件列表
在hdfs上的output目录下查看到运行结果:
./bin/hdfs dfs -cat output/*
得到的结果为
问题:
(1)
在配置ssh无密码连接本地sshd服务的时候出现了找不到目录的情况
后面查资料知道这个并不用先进入文件夹,而是可以直接执行自动创建这个目录
接着要先cd进入目录在执行cat id_rsa.pub >> authorized_keys,否则同样会找不到目标文件
(2)在运行Hadoop示例程序的时候ubuntu卡住了,所以我又重新创建了三个运行容器重新实验,然后在过程中发现,workers这个文件的修改应该得在master的目录下,否则后面在jps查看服务状态的过程种会出现错误,在slave01/02的jps命令下只能看到56Jps这样的情况,而NodeManager和DataNode都不存在。
用时
大概花了两个下午加一个晚上的时间,主要还是花在了第三个实验和第二个实验的javaweb的文件阅读上,最后无奈还是剽一下范例文档的war包。
感觉好多内容都是需要学习的,这种混杂的东西如果有一点不通就经常容易出现错误,就比如第三个实验有的时候某个步骤做错了就得重新开始,感觉特别麻烦,虽然前面有一些存档,不过毕竟还是有一些是无法保存的,但是万幸存档重来其实也节省了许多时间。