一.基础环境
1.配置系统内核转发功能
docker网络依赖于系统的内核转发功能,如果不配置内核转发,docker功能可能会出错
[root@webapi4-app-22-151 ~]# vi /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
[root@webapi4-app-22-151 ~]# sysctl -p
2.安装docker-ce
移除旧版本,如果之前没有安装过docker则跳过
[root@webapi4-app-22-151 ~]# yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
安装工具
[root@webapi4-app-22-151 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
添加docker-ce的yum源
[root@webapi4-app-22-151 ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装docker-ce
[root@webapi4-app-22-151 ~]# yum install -y docker-ce
开启docker
[root@webapi4-app-22-151 ~]# systemctl daemon-reload
[root@webapi4-app-22-151 ~]# systemctl start docker
[root@webapi4-app-22-151 ~]# systemctl enable docker
3.配置镜像仓库
docker默认从国外的DockerHub公共仓库拉取镜像,拉取镜像的速度可能会很慢,所以要配置国内的镜像仓库。
[root@webapi4-app-22-151 ~]#mkdir /etc/docker #如果文件夹已存在则跳过
新建daemon.json文件
[root@webapi4-app-22-151 ~]# cat /etc/docker/daemon.json
{
“registry-mirrors”: [“https://5twf62k1.mirror.aliyuncs.com”]
}
[root@webapi4-app-22-151 ~]# systemctl restart docker
[root@webapi4-app-22-151 ~]#docker info
查看,配置镜像仓库成功
4.拉取镜像
[root@webapi4-app-22-151 ~]# docker pull php:7.3.27-fpm
[root@webapi4-app-22-151 ~]# docker pull nginx:latest
[root@webapi4-app-22-151 ~]# docker pull mysql:8.0
查看当前主机的镜像
二、部署LNMP
新建nginx、php、mysql目录,这三个目录用于保存容器内的配置文件和数据文件,防止删除容器之后导致数据丢失。
[root@webapi4-app-22-151 ~]# mkdir -p /lnmp/{nginx,php,mysql}
[root@webapi4-app-22-151 ~]# mkdir /lnmp/mysql/data
1.搭建mysql
启动一个临时的mysql容器
[root@webapi4-app-22-151 ~]# docker run -itd --name tmp mysql:8.0 /bin/bash
将mysql容器内的配置文件拷贝出来,拷贝到主机的目录
[root@webapi4-app-22-151 ~]# docker cp tmp:/etc/mysql /lnmp/mysql/
删除临时容器
[root@webapi4-app-22-151 mysql]# docker rm -f tmp
配置防火墙,放通端口
[root@webapi4-app-22-151 mysql]# firewall-cmd --add-port=3306/tcp
启动mysql容器
[root@webapi4-app-22-151 mysql]# docker run -d --name mysql -p 3306:3306 --restart always -e MYSQL_ROOT_PASSWORD=000000 -v /lnmp/mysql/mysql/:/etc/mysql -v /lnmp/mysql/data/:/var/lib/mysql mysql:8.0
参数解释
-d:后台运行容器
–name:指定容器名
-p:端口映射,将主机的3306端口与容器的3306端口映射起来。外部访问数据库时可以通过主机的IP:Port来访问,不需要访问容器的IP:Port。
–restart:指定容器的重启策略,always表示总是重启容器,可以实现容器异常退出时自动重启容器
-e:指定容器的环境变量,其中MYSQL_ROOT_PASSWORD=000000表示设置数据库root用户的密码为000000。mysql容器内有脚本可以接收这个参数,如果启动mysql容器时不指定这个环境变量,则容器可能会启动失败。
-v:映射数据卷,其中/lnmp/mysql/mysql/:/etc/mysql表示将主机的/lnmp/mysql/mysql/目录映射为容器的/etc/mysql目录。
查看容器
测试Mysql连接,使用主机的IP:Port访问
连接mysql成功
2.搭建php
启动一个临时的php容器
[root@webapi4-app-22-151 ~]# docker run -itd --name tmp php:7.3.27-fpm
将容器内的配置文件复制到主机目录
[root@webapi4-app-22-151 ~]# docker cp tmp:/usr/local/etc/ /lnmp/php
删除临时容器
[root@webapi4-app-22-151 ~]# docker rm -f tmp
[root@webapi4-app-22-151 ~]# firewall-cmd --add-port=9000/tcp
启动php容器
[root@webapi4-app-22-151 ~]# docker run -itd -p 9000:9000 --name php --restart always -v /lnmp/php/etc/:/usr/local/etc -v /lnmp/nginx/html:/usr/share/nginx/html php:7.3.27-fpm
参数解释
-i:打开容器的标准输入
-t:给容器分配一个终端
3.搭建nginx
启动临时的nginx容器
[root@webapi4-app-22-151 ~]# docker run -d --name tmp nginx:latest
将容器内的网页文件和配置文件拷贝出来,拷贝到主机目录
[root@webapi4-app-22-151 ~]# docker cp tmp:/usr/share/nginx/html/ /lnmp/nginx/
[root@webapi4-app-22-151 ~]# docker cp tmp:/etc/nginx /lnmp/nginx/
删除临时容器
[root@webapi4-app-22-151 ~]# docker rm -f tmp
[root@webapi4-app-22-151 ~]# firewall-cmd --add-port=80/tcp
启动nginx容器
[root@webapi4-app-22-151 ~]# docker run -d --name nginx -p 80:80 --restart always -v /lnmp/nginx/html:/usr/share/nginx/html -v /lnmp/nginx/nginx/:/etc/nginx --link php nginx:latest
参数解释
–link:容器互联,–link php表示nginx容器连接到php容器。设置这个参数之后,nginx容器内的hosts文件会添加一条php容器的IP映射。
网页访问
4.将nginx和php连接起来
添加php测试页面index.php
编辑nginx的配置文件default.conf。(之前nginx容器配置过-v参数的数据卷映射。修改主机目录中的配置文件,那么文件的修改会同步到nginx容器,这样子就省去了进去容器修改文件的麻烦,而且容器内一般是没有vi命令的)
[root@webapi4-app-22-151 ~]# cat /lnmp/nginx/nginx/conf.d/default.conf
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass php:9000;
#之前nginx容器配置过--link php参数,nginx容器可以使用php这个名字来连接
php容器。使用容器的IP来标识php容器不太方便,因为php容器异常重启时容器
的IP可能会变化。
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
完整配置文件:
[root@webapi4-app-22-151 ~]# cat /lnmp/nginx/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
编辑好文件之后,重启nginx容器
[root@webapi4-app-22-151 ~]# docker restart nginx
打开浏览器,访问nginx
三、问题
1.php容器状态异常
php容器一启动就退出,状态异常,一直重启
解决:在启动容器时添加两个参数-it
容器就不会异常退出了
2.nginx连接php失败
添加了php的测试主页index.php,修改了nginx的配置文件来连接php之后,访问nginx主页失败:
用命令“docker logs nginx”查看nginx容器的日志:
2021/04/28 09:55:32 [error] 24#24: *4 FastCGI sent in stderr: “Primary script unknown” while reading response header from upstream, client: 125.218.208.62, server: localhost, request: “GET / HTTP/1.1”, upstream: “fastcgi://172.17.0.3:9000”, host: “192.168.22.151”
解决:编辑nginx的default.conf文件,在location ~ .php$模块中将
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
修改成
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
然后使用命令“docker exec nginx nginx -s reload”重载文件
访问成功
四、DockerSwarm平滑升级PHP版本
一些优秀的容器平台/产品(例如Docker Swarm、Kubernetes、Rancher),集成了“平滑升级应用”的功能,借助这些平台,能够比较顺利、方便地完成应用升级。
上面部署的LNMP是通过docker部署三个容器(mysql容器、php容器、nginx容器)完成的;现在部署的LNMP是通过docker swarm集群(单节点)部署三种服务(mysql服务、php服务、nginx服务)来完成的,每种服务可以包含多个容器,这样的话即使其中一个容器异常那么其他容器也能够正常提供服务。
这里演示PHP从7.3.27版本升级到7.4.16 版本。
删除之前部署的mysql、php、nginx容器
[root@webapi4-app-22-151 ~]# docker rm -f mysql php nginx
查看容器,没有容器在运行
[root@webapi4-app-22-151 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@webapi4-app-22-151 ~]#
之前部署LNMP时用数据卷实现了数据持久化,即使把nginx、mysql、php容器删除,容器的配置文件、数据文件依然存留在主机中。接下来直接引用这些现成的配置文件和数据文件。
1.初始化集群
[root@webapi4-app-22-151 ~]# docker swarm init --advertise-addr 192.168.22.151 #192.168.22.151为当前主机的IP地址
查看集群里的节点
2.创建overlay网络
创建一个名字为lnmp-demo的overlay类型网络。
[root@webapi4-app-22-151 ~]# docker network create --driver overlay lnmp-demo
3.部署LNMP服务
创建PHP服务(7.3.27版本)
[root@webapi4-app-22-151 ~]# docker service create --name php --network lnmp-demo --publish 9000:9000 --mount type=bind,src=/lnmp/php/etc,dst=/usr/local/etc --mount type=bind,src=/lnmp/nginx/html,dst=/usr/share/nginx/html --replicas=4 php:7.3.27-fpm
参数解释
–name:设置服务名称
–network:设置服务的网络
–publish:暴露端口,9000:9000表示把主机的9000端口与容器的9000端口映射起来
–mount:挂载文件系统,bind指主机目录挂载到容器目录
–replicas:设置服务的副本数量,这里值为4,也就是说PHP服务内有4个PHP容器
创建mysql服务
[root@webapi4-app-22-151 ~]# docker service create --name mysql --network lnmp-demo --publish 3306:3306 --replicas=4 --env MYSQL_ROOT_PASSWORD=000000 --mount type=bind,src=/lnmp/mysql/mysql,dst=/etc/mysql mysql:8.0
创建nginx服务
[root@webapi4-app-22-151 ~]# docker service create --name nginx --network lnmp-demo --publish 80:80 --mount type=bind,src=/lnmp/nginx/nginx,dst=/etc/nginx --mount type=bind,src=/lnmp/nginx/html,dst=/usr/share/nginx/html --replicas 4 nginx:latest
查看服务状态
4.连接nginx与php
编辑nginx的default.conf配置文件
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass php:9000;
#三种容器运行在同一个overlay网络,服务之间可以用服务名或服务的虚拟IP来通信。
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
完整配置文件:
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
重启nginx服务内的所有容器
[root@webapi4-app-22-151 ~]# docker restart $(docker ps -a -f name=nginx --format ‘{{.Names}}’)
访问nginx主页,可以看到当前PHP版本是7.3.27
升级PHP
Docker Swarm更新版本时,先停止一个旧版本容器,然后启动一个新版本容器,隔一段时间之后再停止一个旧版本容器、启动一个新版本容器,一直到所有旧版本容器停止、所有新版本容器启动完成,更新完成。
执行docker service update命令,对PHP服务进行升级
[root@webapi4-app-22-151 ~]# docker service update --image php:7.4.16-fpm --update-parallelism 1 --update-delay 10s --update-max-failure-ratio 0.5 --update-failure-action pause php
参数解释
–image: 设置更新的镜像,这里用php:7.4.16-fpm,也就是把PHP服务的镜像换成php:7.4.16-fpm镜像,即升级为7.4.16版本
–update-parallelism :设置并行更新的副本数,这里设置为1,也就是停止1个旧版本容器,启动1个新版本容器。设置为2的话则表示每停止2个旧版本容器,启动2个新版本容器。
–date-delay:更新间隔,这里设置为10秒。也就是更新一次容器之后,过10秒再进行下一次更新。
–update-max-failure-ratio:更新期间可以容忍的故障率,这里设置为0.5即50%,也就是说如果更新过程中有50%容器更新失败那么就认为此次更新是失败的,与–update-failure-action参数搭配使用。
–update-failure-action:设置更新失败之后的策略,pause表示更新失败之后停止更新,与上面的–update-max-failure-ratio参数连用,两个参数结合起来的作用是:当50%容器更新失败之后,就停止更新。另外,–update-failure-action还可以设置成rollback,即更新失败后自动回滚上一个版本。
更新过程:
更新完成,可以看到PHP服务已经升级到7.4.16版本。
访问更新PHP之后的Nginx
至此,PHP版本升级完成
更新之后,旧版本容器没有被删除,占用空间
删除旧版本容器,docker rm $(docker ps -qa -f status=exited)
6.回滚测试
现在PHP已经升级到7.4.16版本,如果想要PHP回滚成旧的7.3.27版本,可以使用docker swarm的rollback功能来实现:
五、DockerSwarm升级应用遇到的问题
1 . File not found
执行以下三条命令部署三种服务
并且连接了nginx和php之后,访问nginx主页显示File not found:
原因是三种服务运行没有运行在overlay网络中,导致服务之间无法通过服务名来通信。
解决:删除三种服务,然后新建overlay网络,让三种服务运行在同一个overlay网络中
就可以正常显示网页了