通过前面几次的实验,大家已经基本熟悉Docker、Dockerfile、Docker Compose的相关操作,从本次实验开始,将结合此前相关课程内容,安排一些相关技术专题实践:
(1)使用Docker-compose实现Tomcat+Nginx负载均衡
要求:
理解nginx反向代理原理;
nginx代理tomcat集群,代理2个以上tomcat;
了解nginx的负载均衡策略,并至少实现nginx的2种负载均衡策略;
参考资料:
Docker下Nginx+Tomcat实现负载均衡
使用docker-compose搭建反向代理nginx+tomcat页面
实战docker,构建nginx反向代理tomcat,学习link和docker-compose
nginx使用Upstream实现负载均衡
浅谈docker-compose网络设置之networks
一:
正向代理
正向代理服务器位于客户端和服务器之间,为了向服务器获取数据,客户端要向代理服务器发送一个请求,并指定目标服务器,代理服务器将目标服务器返回的数据转交给客户端。这里客户端是要进行一些正向代理的设置的。
反向代理
反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址。
二:
首先,从docker仓库中拉取nginx和tomcat镜像
docker pull nginx
docker pull tomcat
创建工程目录
然后编写nginx.conf和dockerfile_nginx
dockerfile_nginx
FROM docker.io/nginx
#使用的原镜像
ENV WORK_PATH /etc/nginx
#设置变量 WORK_PATH= /etc/nginx
WORKDIR /etc/nginx
#设置默认当前路径为/etc/nginx
ENV NGINX_FILE_CONF nginx.conf
#设置变量NGINX_FILE_CONF=nginx.conf
RUN rm $NGINX_FILE_CONF
#删除原有的nginx.conf文件
COPY nginx.conf .
#把目录下的 nginx.conf复制到容器当前
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
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"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
upstream tomcat_client {
server tomcat1:8080 weight=1;
server tomcat2:8080 weight=1;
server tomcat3:8080 weight=1;
}
server {
server_name "";
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
location / {
proxy_pass http://tomcat_client;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
编写docker-compose.yml
version: "3"
services:
tomcat1:
image: tomcat:latest
volumes:
- ./tomcat1/:/usr/local/tomcat/webapps/ROOT/
restart: "always"
container_name: tomcat1
tomcat2:
image: tomcat:latest
volumes:
- ./tomcat2/:/usr/local/tomcat/webapps/ROOT/
container_name: tomcat2
restart: "always"
tomcat3:
image: tomcat:latest
volumes:
- ./tomcat3/:/usr/local/tomcat/webapps/ROOT/
container_name: tomcat3
restart: "always"
nginx:
image: nginx:latest
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
links:
- tomcat1:t1
- tomcat2:t2
- tomcat3:t3
运行docker-compose.yml
轮询策略(就是upstream默认的策略)
权重策略(修改nginx.conf,为t1,t2,t3选择合适的权重值,nginx会根据权重来选择访问的服务器,权重越高越优先)
可以看到tomcat3出现的次数明显更多
(2) 使用Docker-compose部署javaweb运行环境
要求:
分别构建tomcat、数据库等镜像服务;
成功部署Javaweb程序,包含简单的数据库操作;
为上述环境添加nginx反向代理服务,实现负载均衡。
工程目录
其中nginx与tomcat的配置几乎没变,这里就不贴出来了
dockerfile_mysql
FROM mysql:5.7
MAINTAINER wcx
WORKDIR /usr/local/
ENV MYSQL_ROOT_PASSWORD 123456
ENV MYSQL_ALLOW_EMPTY_PASSWORD no
COPY schema.sql /usr/local/
COPY setup.sh /usr/local/
RUN chmod a+x /usr/local/setup.sh
ENTRYPOINT ["/usr/local/setup.sh"]
EXPOSE 80
setup.sh
#!/bin/bash
set -e
#查看mysql服务的状态,方便调试,这条语句可以删除
echo `service mysql status`
echo '1.启动mysql....'
#启动mysql
service mysql start
sleep 3
echo `service mysql status`
echo '2.开始导入数据....'
#导入数据
mysql < /usr/local/schema.sql
echo '3.导入数据完毕....'
sleep 3
echo `service mysql status`
#sleep 3
echo `service mysql status`
echo `mysql容器启动完毕,且数据导入成功`
sleep 3
echo `重新启动mysql服务`
service mysql restart
tail -f /dev/null
schema.sql
CREATE database `testDatabase` default character set utf8 collate utf8_general_ci;
use testDatabase;
DROP TABLE IF EXISTS testTable;
CREATE TABLE testTable(
`id` varchar(20) UNIQUE,
`name` varchar(10) NOT NULL,
`sex` varchar(1) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO testTable
VALUES
('1','testname','m'),('2','test1','w');
docker-compose.yml
version: '2'
services:
mysql:
image: mysqlimage
container_name: mysqlimage
build:
context: ./mysql/
dockerfile: dockerfile_mysql
volumes:
- ./mysql:/usr/local/
restart: always
tomcat1:
image: tomcat:latest
volumes:
- ./tomcat1/:/usr/local/tomcat/webapps/
restart: "always"
container_name: tomcat1
links:
- mysql:mysql
tomcat2:
image: tomcat:latest
volumes:
- ./tomcat2/:/usr/local/tomcat/webapps/
links:
- mysql:mysql
container_name: tomcat2
restart: "always"
tomcat3:
image: tomcat:latest
volumes:
- ./tomcat3/:/usr/local/tomcat/webapps/
links:
- mysql:mysql
container_name: tomcat3
restart: "always"
nginx:
image: nginx
build:
context: ./nginx
dockerfile: dockerfile_nginx
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
links:
- tomcat1:t1
- tomcat2:t2
- tomcat3:t3
增加数据
更新数据
删除数据
参考资料:
使用docker-compose部署Javaweb项目
手把手搭建javaweb项目,适合新手
tomcat+nginx-mysql
(3)使用Docker搭建大数据集群环境
直接用机器搭建Hadoop集群,会因为不同机器配置等的差异,遇到各种各样的问题;也可以尝试用多个虚拟机搭建,但是这样对计算机的性能要求比较高,通常无法负载足够的节点数;使用Docker搭建Hadoop集群,将Hadoop集群运行在Docker容器中,使Hadoop开发者能够快速便捷地在本机搭建多节点的Hadoop集群。
要求:
完成hadoop分布式集群环境配置,至少包含三个节点(一个master,两个slave);
成功运行hadoop 自带的测试实例。
一、构建ubuntu:hadoop
工程目录
dockerfile
FROM ubuntu:18.04
MAINTAINER wcx
COPY hadoop.zip /usr/local/
COPY sources.list /etc/apt/
RUN apt-get update && apt-get install -y \
vim \
openjdk-8-jdk \
ssh
EXPOSE 80
source.list是国内源文件
hadoop.zip是hadoop3.1.3的压缩包
使用docker build -t ubuntu:hadoop .构建镜像
docker build -t ubuntu:hadoop .
进入ubuntu:hadoop镜像
docker run -it ubuntu:hadoop /bin/bash
在该镜像中解压/usr/local/hadoop.zip(apt-get install unzip)
unzip hadoop.zip
配置java,hadoop的环境变量
vim ~/.bashrc
添加如下代码
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/usr/local/hadoop
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin:$JAVA_HOME/bin
然后source ~/.bashrc使之生效
检验hadoop和java
配置ssh免密登陆
ssh-keygen -t rsa # 一直按回车即可
cd ~/.ssh
cat id_rsa.pub >> authorized_keys
输入ssh localhost验证一下
此时可以进入到下一个阶段:hadoop文件配置
首先进入hadoop/etc/hadoop
配置hadoop-env
配置core-site.xml
在
<property>
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
配置hdfs-site.xml
在
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
配置mapred-site.xml
在
<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</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
配置yarn-site.xml
操作同上
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>Master</value>
</property>
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>2.5</value>
</property>
进入hadoop脚本目录(sbin)
配置start-dfs.sh 和stop-dfs.sh
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USR=root
HDFS_SECONDARYNAMENODE_USER=root
配置start-yarn.sh和stop-yarn.sh
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
退出容器,接着用该容器构建新的镜像ubuntu-hadoop
docker commit 容器ID 新镜像名
运行三个终端,
docker run -it -h 主机名 --name 容器名 镜像名
查看三个主机的ip地址
sudo docker inspect --format='{{.NetworkSettings.IPAddress}}' 名字
进入master容器,配置/usr/local/hadoop/etc/hadoop/workers(将localhost删去,改为slave1和slave2)
分别对三个主机的/etc/hosts进行修改,添加如下内容
172.17.0.2 master
172.17.0.3 slave1
172.17.0.4 slave2
互相ssh测试
差不多就能确定可以互相登陆
进入master主机,初始化namenode等
hdfs namenode -format #初始化namenode
start-dfs.sh #启动HDFS
start-yarn.sh #启动YARN
到此hdfs完全分布式环境已搭建完毕
运行案例grep
在master上执行如下命令
hdfs dfs -mkdir -p /user/root/input #新建input文件夹
hdfs dfs -put /usr/local/hadoop/etc/hadoop/*s-site.xml input #将部分文件放入input文件夹
hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar grep input output 'dfs[a-z.]+' #运行示例程序grep
hdfs dfs -cat output/*
参考资料:
Hadoop 参考文档
使用Docker搭建Hadoop分布式集群
(4)遇到的问题
这个是因为在nginx的配置项extnetwork:中的ipv4_address的' : '后没加空格,属于格式问题
2.
这个是因为没用sudo执行docker-compose命令
首先,查看docker images和docker container ,发现mysql镜像已经成功创建,而相应容器却仍停留在created状态,说明容器虽能创建成功,却无法启动。
尝试进入该容器,成功。检查要上传的文件(setup.sh等),发现已存在在该容器中。尝试手动在该容器中运行setup.sh,发现schema.sql中存在语法问题。修正schema.sql,重新compose up,却依旧是出现同样的错误。经老师与同学的帮助,在dockrfile中用ENTRYPOINT命令代替CMD命令为setup.sh赋予权限,并在本地也赋予setup.sh的权限。再次compose up,容器启动成功。但当进入mysql容器时,每次都会执行setup.sh,且执行完无响应,即无法进入容器的命令行界面。于是猜测是setup.sh的问题,经过尝试,在setup.sh中增加一句service mysql restart后容器运行正常。(不是很懂这个,有知道的大佬可以评论一下咩╮(╯_╰)╭)
又是这个。。。这个是因为master节点执行了多次hdfs namenode -format导致clusterID与slave1和slave2的不同,因此打开master的hdfs-site.xml文件查看namenode的存放文件,再进入该文件中,找到current/VESION,cat一下,复制里面的clusterID,然后进入slave节点,同上找到datanode的存放目录,找到current/VERSION,将里面的clusterID改为master的clusterID后,执行stop-dfs.sh等命令重启hdfs集群,再重新建立相应的输入输出文件夹,执行测试程序,便可成功运行。
5.
执行测试程序时界面卡在Job running这句。
解决方法:
将mapred-site.xml中的
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
替换为
<property>
<name>mapreduce.job.tracker</name>
<value>hdfs://此处为自己的电脑IP:8001</value>
<final>true</final>
</property>
替换后程序运行飞快,很流畅。