通过前面几次的实验,大家已经基本熟悉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>

替换后程序运行飞快,很流畅。