7

简介

对于企业应用架构来说,肯定不局限于一台服务器,按照我的设想:至少一台部署后台接口的服务器;一台部署前端页面的服务器;一台做代理的服务器;一台装载数据库的服务器等等,这还不包括对某些应用做负载均衡。
可是慷慨的许姓朋友只能赞助我一台服务器,这时候我就想到了Docker。只要我多开几个容器,就能模拟分出多个服务器,对应多个IP。
所以本章首先是讲解安装Docker,其次是一一示例如何在Docker容器中安装配置Nginx、Tomcat和MySQL。原计划数据库使用Oracle,但是由于服务器配置太低,每次Oracle容器运行起来后都会导致服务器宕机,所以不得不改为MySQL。
由于考虑到Docker容器每次重启都会从镜像中初始化,文章中会大量使用到挂载,具体原理最后章节会讲。

Docker安装

1、使用uname -r 查看系统内核,Docker 要求CentOS系统的内核版本高于 3.10

[root@VM_60_202_centos ~]# uname -r   
3.10.0-862.9.1.el7.x86_64

2、做好准备,确认yum更新到最新,没有安装过旧版本Docker

[root@VM_60_202_centos ~]# yum update    --最新版yum包
[root@VM_60_202_centos ~]# yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine docker.io
                                         --删除旧版本Docker

3、安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的

[root@VM_60_202_centos ~]# yum install -y yum-utils device-mapper-persistent-data lvm2

4、最新版本的 Docker 分两个版本,docker-ce(Community Edition)和docker-ee(Enterprise Edition)。CE版本是免费的,如果我们学习或者一般应用,CE足够。我们安装社区版。下面可以设置数据源仓库,可以选用Docker官方数据源或者阿里云数据源:

[root@VM_60_202_centos ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
--添加官方数据源

[root@VM_60_202_centos ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
--添加阿里云数据源

5、安装Docker

[root@VM_60_202_centos ~]# yum list docker-ce --showduplicates | sort -r  
--列出可以安装的docker版本
[root@VM_60_202_centos ~]# yum install docker-ce     
--下载最新版本
[root@VM_60_202_centos ~]# yum install -y docker-ce-18.03.1.ce-1.el7.centos 
--安装指定版本

6、启动Docker

[root@VM_60_202_centos ~]# systemctl start docker    --启动
[root@VM_60_202_centos ~]# systemctl stop docker     --关闭
[root@VM_60_202_centos ~]# systemctl restart docker  --重启

7、验证安装情况

[root@VM_60_202_centos ~]# docker --version  --查看安装的docker版本
[root@VM_60_202_centos ~]# docker run hello-world

Tomcat容器

1、从数据源中查找Tomcat镜像。一般下载官方的镜像Starts最高的那个。

[root@VM_60_202_centos ~]# docker search tomcat    --查询tomcat官方镜像
[root@VM_60_202_centos ~]# docker pull tomcat      --下载下来其中的名为“tomcat”的镜像
[root@VM_60_202_centos ~]# docker images           --查看本地所有的镜像

clipboard.png

2、宿主机创建挂载目录,启动Tomcat容器

[root@VM_60_202_centos ~]# mkdir -p /u01/tomcat/webapps/tomcat1
--创建目录/u01/tomcat/webapps/tomcat1,用于挂载Tomcat的

[root@VM_60_202_centos ~]# mkdir -p /u01/tomcat/webapps/tomcat2
--创建目录/u01/tomcat/webapps/tomcat2,用于挂载Tomcat的
--并分别在/u01/tomcat/webapps/tomcat1和/u01/tomcat/webapps/tomcat2中放置已经准备好的不同的war包(虽然都是kerryNginxServlet.war,但内容不同)

[root@VM_60_202_centos ~]# docker run --name=my_tomcat1 -v /u01/tomcat/webapps/tomcat1:/usr/local/tomcat/webapps -p 8001:8080 -d tomcat
--启动一个Tomcat容器,命名为my_tomcat1;将容器的8080端口映射到宿主机的8001
--将宿主机的/u01/tomcat/webapps/tomcat1 目录挂载到容器上的/usr/local/tomcat/webapps 目录

[root@VM_60_202_centos ~]# docker run --name=my_tomcat2 -v /u01/tomcat/webapps/tomcat2:/usr/local/tomcat/webapps -p 8002:8080 -d tomcat
--再运行一个Tomcat容器,命名my_tomcat2,用于做负载均衡

3、验证Tomcat容器

[root@VM_60_202_centos ~]# curl http://localhost:8001/kerryNginxServlet/servletA
<h2> hello I am Kerry!</h2><h1>This is the servlet test A!</h1>

[root@VM_60_202_centos ~]# curl http://localhost:8002/kerryNginxServlet/servletA
<h2> hello I am Kerry!</h2><h1>This is the servlet test B!</h1> 

Nginx容器

1、同样,从数据源中查找Nginx镜像。一般下载官方的镜像Starts最高的那个。

[root@VM_60_202_centos ~]# docker search nginx    --查询nginx官方镜像
[root@VM_60_202_centos ~]# docker pull nginx      --下载下来其中的名为“nginx”的镜像
[root@VM_60_202_centos ~]# docker images           --查看本地所有的镜像

clipboard.png

2、宿主机创建挂载目录,编辑配置文件

[root@VM_60_202_centos ~]# mkdir -p /u01/nginx
[root@VM_60_202_centos ~]# mkdir -p /u01/nginx/conf.d
[root@VM_60_202_centos ~]# touch /u01/nginx/nginx.conf
[root@VM_60_202_centos ~]# touch /u01/nginx/conf.d/default.conf

然后vi 编辑 /u01/nginx/nginx.conf 文件

user  root;
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 tomcatServer {
      server t1:8080;
      server t2:8080;
    }
}

编辑 /u01/nginx/conf.d/default.conf 文件

server {
    listen       80;
    server_name localhost;
    location / {
        proxy_pass   http://tomcatServer;
    }
}

3、启动Nginx容器

[root@VM_60_202_centos ~]# docker run --name=my_nginx1 --link=my_tomcat1:t1 --link=my_tomcat2:t2 -v /u01/nginx/nginx.conf:/etc/nginx/nginx.conf -v /u01/nginx/conf.d:/etc/nginx/conf.d -p 8000:80 -d nginx
--运行Nginx的容器,命名为my_nginx1
--给my_tomcat1、my_tomcat2容器分别起别名,t1、t2(会在my_nginx1的/etc/hosts文件中自动配置)
--挂载/u01/nginx/nginx.conf文件和/u01/nginx/conf.d目录
--将容器的端口号80映射到宿主机的8000端口

[root@VM_60_202_centos ~]# curl http://localhost:8000/kerryNginxServlet/servletA
<h2> hello I am Kerry!</h2><h1>This is the servlet test A!</h1>

[root@VM_60_202_centos ~]# curl http://localhost:8000/kerryNginxServlet/servletA
<h2> hello I am Kerry!</h2><h1>This is the servlet test B!</h1>

因为配置了负载均衡,所以在访问http://localhost:8000/kerryNginxServlet/servletA时,会有平均概率地访问http://localhost:8001/kerryNginxServlet/servletA 和 http://localhost:8002/kerryNginxServlet/servletA

MySQL容器

1、从数据源中查找MySQL镜像。一般下载官方的镜像Starts最高的那个。

[root@VM_60_202_centos ~]# docker search mysql    --查询mysql官方镜像
[root@VM_60_202_centos ~]# docker pull mysql      --下载下来其中的名为“mysql”的镜像
[root@VM_60_202_centos ~]# docker images           --查看本地所有的镜像

2、创建挂载目录

[root@VM_60_202_centos ~]# mkdir -p /u01/mysql/data /u01/mysql/logs /u01/mysql/conf

--data目录将映射为mysql容器配置的数据文件存放路径
--logs目录将映射为mysql容器的日志目录
--conf目录里的配置文件将映射为mysql容器的配置文件

3、启动MySQL容器

docker run -p 3306:3306 --name my_mysql1 -v /u01/mysql/conf:/etc/mysql/conf.d -v /u01/mysql/logs:/logs -v /u01/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=kerry -d mysql

-p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口。
-v 挂载。
-e MYSQL_ROOT_PASSWORD=kerry:初始化 root 用户的密码。

4、远程连接数据库
这时远程来连接该数据库,可能会报错:

ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded

在安装mysql8的时候如果选择了密码加密,之后用客户端连接比如navicate,会提示客户端连接caching-sha2-password,是由于客户端不支持这种插件,可以通过如下方式进行修改:
1)进入容器

docker exec -it my_mysql1 bash

2)进入mysql

mysql -uroot -pkerry

3)修改用户登录权限信息
先查询用户信息

mysql> select host,user,plugin,authentication_string from mysql.user;
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
| host      | user             | plugin                | authentication_string                                                  |
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
| %         | root             | caching_sha2_password | *B9C0EAD50A12474280CBCFD8CFB40DF416A93E02                              |
| localhost | mysql.infoschema | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.session    | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.sys        | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | root             | mysql_native_password | *B9C0EAD50A12474280CBCFD8CFB40DF416A93E02                              |
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
5 rows in set (0.00 sec)

host为 % 表示不限制ip localhost表示本机使用 plugin非mysql_native_password 则需要修改密码。
上文中可以见,root用户不限制ip,但需要修改 plugin。当然,如果为了应对各种应用场景,可以统一执行下列SQL:

ALTER USER 'root'@'%' IDENTIFIED BY 'kerry' PASSWORD EXPIRE NEVER; 
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'kerry'; 
FLUSH PRIVILEGES; #刷新权限 

改完之后,就可以用其他客户端连接该数据库了。此时查询数据库的用户信息为:

mysql> select host,user,plugin,authentication_string from mysql.user;
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
| host      | user             | plugin                | authentication_string                                                  |
+-----------+------------------+-----------------------+------------------------------------------------------------------------+
| %         | root             | mysql_native_password | *B9C0EAD50A12474280CBCFD8CFB40DF416A93E02                              |
| localhost | mysql.infoschema | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.session    | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.sys        | caching_sha2_password | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | root             | mysql_native_password | *B9C0EAD50A12474280CBCFD8CFB40DF416A93E02                              |
+-----------+------------------+-----------------------+------------------------------------------------------------------------+

其他

1、挂载的原理
Docker内的文件系统工作情况。Docker镜像被存储在一系列的只读层。当我们开启一个容器,Docker读取只读镜像并添加一个读写层在顶部。如果正在运行的容器修改了现有的文件,该文件将被拷贝出底层的只读层到最顶层的读写层。在读写层中的旧版本文件隐藏于该文件之下,但并没有被不破坏 - 它仍然存在于镜像以下。当Docker的容器被删除,然后重新启动镜像时,将开启一个没有任何更改的新的容器 - 这些更改会丢失。此只读层及在顶部的读写层的组合被Docker称为Union File System(联合文件系统)。
为了能够保存(持久)数据以及共享容器间的数据,Docker提出了Volumes的概念。很简单,volumes是目录(或者文件),它们是外部默认的联合文件系统或者是存在于宿主文件系统正常的目录和文件。
2、MySQL的表数据等,在本地宿主机上存储的策略尚不完整,后续会另起篇幅,拿实际项目举例说明。


KerryWu
641 声望159 粉丝

保持饥饿