docker 安装 lnmp

技术文章请注意时效!原理才是根本。

本文参考docker_practice:https://github.com/yeasy/docker_practice

为什么使用docker?

切换服务器的时候,需要把所有的环境都安装一遍,这样是很麻烦的。在早先的文章中就提到了各种备份方式,最好的方式是在主机上安装一个虚拟机,备份虚拟机就好了。但是早些虚拟主机是全虚拟化,就像vmvare一样,虚拟了一整套硬件资源,是在本地os上面又加了一层虚拟层,比较笨重。docker直接使用本地os,和传统虚拟化以及半虚拟化相比,容器不需要模拟层(emulation layer)和管理层(hypervisor layer),而是使用操作系统的系统调用接口。这降低了运行单个容器所需的开销,也使得宿主机中可以运行更多的容器。

docker安装

这里使用的是ubuntu server 16.04 64位的系统。

1. 卸载旧版本
旧版本的 Docker 称为 docker 或者 docker-engine ,使用以下命令卸载旧版本:
apt-get remove docker docker-engine docker.io

2. 安装 Docker CE
add-apt-repository “deb https://download.docker.com/linux/ubuntu zesty edge”
更新 apt 软件包缓存,并安装 docker-ce :
apt-get update
apt-get install docker-ce -y –allow-unauthenticated
docker -v

3.开机启动

4.配置docker镜像服务器(可以不用)
nano /etc/docker/daemon.json

5.docker重启

/etc/init.d/docker stop
/etc/init.d/docker start

docker常用命令

1.搜索镜像
docker search 镜像名称

2. 列出本地镜像
docker images

3. 拉取镜像
docker pull mysql

4. 删除镜像
docker rmi $IMAGE_ID #删除指定镜像
docker rmi docker images -q #删除所有镜像,这不是单引号

5. 保存和恢复镜像
docker save -o /docker/images/nginx.tar nginx #保存 nginx 镜像到 /docker/images/nginx.tar
docker load -i mynginx.tar #从备份文件中恢复镜像

6. 运行交互式 docker 容器
docker run -it –name=ubuntu ubuntu:16.04 /bin/bash
-i:表示运行容器。
-t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
–name : 为创建的容器命名。
/bin/bash:指的是容器运行后,启动的交互程序

7. 运行守护式 docker 容器
docker run -id –name=ubuntu ubuntu:16.04 /bin/bash
-d:创建守护式容器在后台运行
登录守护式容器方式:
docker exec -it ubuntu /bin/bash #exit 退出时,容器不会停止

8. 停止与启动容器
docker stop $CONTAINER_NAME/ID
docker start $CONTAINER_NAME/ID

9. 查看 docker 容器
docker ps -a

10. 删除 docker 容器
docker stop xxx #xxx 是容器名字,或者 id
docker rm xxx
docker stop docker ps -a -q #停止所有 docker 容器
docker rm docker ps -a -q

11.docker 容器和宿主机拷贝文件
docker cp 容器名称:容器目录 宿主机目录
docker cp 宿主机目录 容器名称:容器目录

12. 挂载主机目录到容器
docker run -di -v /usr/local/myhtml:/usr/local/myhtml –name=mycentos centos:7
-v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v 做多个目录或文件映射。如果主机没有对应文件夹,会自动建立。

docker容器和主机文件共享

1.docker 容器和宿主机拷贝文件
docker cp 容器名称:容器目录 宿主机目录
docker cp 宿主机目录 容器名称:容器目录

2. 挂载主机目录到容器
docker run -di -v /usr/local/myhtml:/usr/local/myhtml –name=mycentos centos:7
-v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v 做多个目录或文件映射。

3. 创建数据卷
创建一个数据卷
docker volume create my-vol
查看所有的 数据卷
docker volume ls
查看指定 数据卷 的信息
docker volume inspect my-vol
启动一个挂载数据卷的容器
docker run -id –name=web –mount source=my-vol,target=/webapp ubuntu
实验证明和 – v 参数的作用是一样的,只要两个容器共用同一个数据卷或者主机目录,一个对这个数据卷或主机目录的更改会影响另一个。主机对数据卷或者共享目录的更改,也会立即影响到两个容器。

docker容器之间的通信

方法一:把每个容器的服务地址端口映射到主机的端口上,通过主机端口互相访问。
方法二:通过 docker 的命令 – link name 访问。比如 nginx 容器中 fastcgi_pass 的值从 127.0.0.1:9000 改为了 phpfpm:9000,这里的 phpfpm 是域名,在 nginx 容器的 /etc/hosts 文件中自动配置为 phpfpm 容器的访问 IP。原理参考 docker 之间的通信。
方法三:自定义的 Docker 网络来连接多个容器,取代–link 参数。

docker部署lnmp思路

a)不能把所有的服务 mysql,nginx,php 都放到一个 docker 中,需要每个服务部署一个 docker,解耦服务。
b)创建数据卷,用于主机和 docker 容器的文件通信,这里使用 – v 参数。
c)docker 容器间通信,比如 nginx 的容器需要访问 php 的解析服务,php 需要访问 mysql。这里使用自定义的 Docker 网络来连接多个容器。
d)nginx 的 docker 容器的 /usr/share/nginx/html 中保存着 php 文件,映射到了主机上 /docker/nginx/data/html 目录。同时 php-fpm 的 docker 容器的 /usr/share/nginx/html 也映射到主机中的 /docker/nginx/data/html 目录。所以 nginx 容器访问 php 文件的时候,实际访问的是 php 容器下的 /usr/share/nginx/html,也就是主机中的 /docker/nginx/data/html 目录。
对应 nginx 配置文件:nginx.conf

创建公共网桥

docker部署php-fpm

1. 创建相关文件夹
mkdir -p /docker/php/docker-file
mkdir -p /docker/php/conf mkdir -p /docker/php/data mkdir -p /docker/php/logs

2. 下载 nginx 容器
docker pull bitnami/php-fpm

3. 配置文件
docker run -id –restart=always –name=php -v /docker/nginx/data/html:/usr/share/nginx/html –network docker-bridge-net bitnami/php-fpm

4. 保存镜像
mkdir -p /docker/images
docker save -o /docker/images/bitnami-php-fpm.tar bitnami/php-fpm

docker部署nginx

1. 创建相关文件夹
mkdir -p /docker/nginx/docker-file
mkdir -p /docker/nginx/data/html /docker/nginx/logs /docker/nginx/conf /docker/nginx/conf/httpscert
// 必须先建立配置文件,docker 只会自动建立文件夹
touch /docker/nginx/conf/nginx.conf

#和 https 相关的文件
touch /docker/nginx/conf/httpscert/www.xxx.com/fullchain.pem
touch /docker/nginx/conf/httpscert/www.xxx.com/privkey.pem
touch /docker/nginx/conf/httpscert/www.xxx.com/dhparam.pem

2. 下载 nginx 容器
docker pull nginx

3. 配置文件
nano /docker/nginx/conf/nginx.conf

4. 运行 nginx 容器
docker run -id –restart=always –name=nginx
-v /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
-v /docker/nginx/conf/httpscert:/etc/nginx/httpscert:ro
-v /docker/nginx/conf/conf.d:/etc/nginx/conf.d
-v /docker/nginx/logs:/var/log/nginx
-v /docker/nginx/data/html:/usr/share/nginx/html
-p 80:80 -p 443:443 –network docker-bridge-net nginx

5. 打开防火墙端口
ufw allow 80
ufw allow 443
ufw reload

6. 保存镜像
mkdir -p /docker/images
docker save -o /docker/images/nginx.tar nginx

docker部署let’s encrypt

1. 安装 certbot
pip3 install certbot #不知道为什么这家 vps 的提供商这样安装会报错,网上的解决方法也不管用。采用下面的方式安装。

#certbot-auto 脚本可以创建一个虚拟的 python 环境,没有这种问题
wget https://dl.eff.org/certbot-auto -O /usr/sbin/certbot-auto
chmod a+x /usr/sbin/certbot-auto
certbot-auto

2. 生成证书
certbot-auto certonly –webroot -w /docker/nginx/data/html -d www.xxx.com -m xxx@gmail.com –agree-tos
/docker/nginx/data/html 这个目录是 nginx 容器映射到宿主机上的目录,验证程序需要在网站目录读写一个文件,来验证这台服务器拥有这个域名。
生成 dhparam.pem 文件
mkdir /etc/ssl/private/ -p
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem

#复制证书文件到 nginx
mkdir -p /docker/nginx/conf/httpscert/www.xxx.com
cp -f /etc/letsencrypt/live/www.xxx.com/fullchain.pem/docker/nginx/conf/httpscert/www.xxx.com/fullchain.pem
cp -f /etc/letsencrypt/live/www.xxx.com/privkey.pem /docker/nginx/conf/httpscert/www.xxx.com/privkey.pem
cp -f /etc/ssl/private/dhparam.pem /docker/nginx/conf/httpscert/www.xxx.com/dhparam.pem
chmod 400 /etc/letsencrypt/live/www.xxx.com/fullchain.pem
chmod 400 /etc/letsencrypt/live/www.xxx.com/privkey.pem
chmod 400 /etc/ssl/private/dhparam.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/fullchain.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/privkey.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/dhparam.pem

3.nginx 配置 ssl 访问
nano /docker/nginx/conf/nginx.conf

docker部署mysql

1. 创建相关文件夹
mkdir -p /docker/mysql/docker-file
mkdir -p /docker/mysql/data /docker/mysql/logs /docker/mysql/conf

2. 下载镜像
docker pull mysql:5.7

3. 配置文件
nano /docker/mysql/conf/mysql-custom.cnf

4. 运行 mysql docker 容器
docker run -id –restart=always –name=mysql -v /docker/mysql/data:/var/lib/mysql -v /docker/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=xxx –network docker-bridge-net -p 3306:3306 mysql:5.7
虽然映射了端口到主机,但是不要打开防火墙,是为了本机的备份服务。

5. 保存镜像
mkdir -p /docker/images
docker save -o /docker/images/mysql.tar mysql

wordpres部署

把wordpress解压到/docker/nginx/data/html,修改wp-config.php

docker备份恢复

为什么不用 docker commit xxx_nginx mynginx 保存容器?
xxx_nginx 是容器名称
mynginx 是新的镜像名称
比如 mysql,直接 commit mysql 的 docker 容器,发现 mysql 中的数据库 data 并没有保存下来,原因是 mysql 的 docker 镜像中是通过挂在数据卷的方式来写入数据库中的数据,可以在 /var/lib/volumes/xxxxxxxxxxxxxxxxxxxxx/_data 中找到。而数据卷中的数据是不会被保存下来的。在 mysql:5.7 的镜像 docker file 中可以看到相关信息。
所以最好的实践,就是创建 docker 容器的时候自己指定主机到 docker 中路径的映射,恢复的时候直接恢复就好了。

1. 备份 docker 中的数据
mkdir /backup
tar cvpzf /backup/backup-$(date +%Y%m%d-%H%M).tgz /docker
-p :使用原文件的原来属性(属性不会依据使用者而变)

2. 恢复 docker 中的数据
tar xvpzf /backup/backup-20181001-1630.tgz -C /

3. 从文件中恢复镜像,-i 输入的文件
docker load -i /docker/images/nginx.tar
docker load -i /docker/images/mysql.tar
docker load -i /docker/images/bitnami-php-fpm.tar
docker images 查看镜像

4. 恢复 php-fpm 服务
docker run -id –restart=always –name=php -v /docker/nginx/data/html:/usr/share/nginx/html –network docker-bridge-net bitnami/php-fpm

5. 恢复 nginx 服务
docker run -id –restart=always –name=nginx
-v /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
-v /docker/nginx/conf/httpscert:/etc/nginx/httpscert:ro
-v /docker/nginx/conf/conf.d:/etc/nginx/conf.d
-v /docker/nginx/logs:/var/log/nginx
-v /docker/nginx/data/html:/usr/share/nginx/html
-p 80:80 -p 443:443 –network docker-bridge-net nginx
ufw allow 80
ufw allow 443
ufw reload

6. 生成 https 需要的证书
mkdir /etc/ssl/private/ -p
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem

#let’s encrypt
certbot-auto certonly –webroot -w /docker/nginx/data/html -d www.xxx.com -m xxx@gmail.com –agree-tos

#复制证书文件到 nginx
mkdir -p /docker/nginx/conf/httpscert/www.xxx.com
cp -f /etc/letsencrypt/live/www.xxx.com/fullchain.pem/docker/nginx/conf/httpscert/www.xxx.com/fullchain.pem
cp -f /etc/letsencrypt/live/www.xxx.com/privkey.pem /docker/nginx/conf/httpscert/www.xxx.com/privkey.pem
cp -f /etc/ssl/private/dhparam.pem /docker/nginx/conf/httpscert/www.xxx.com/dhparam.pem
chmod 400 /etc/letsencrypt/live/www.xxx.com/fullchain.pem
chmod 400 /etc/letsencrypt/live/www.xxx.com/privkey.pem
chmod 400 /etc/ssl/private/dhparam.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/fullchain.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/privkey.pem
chmod 400 /docker/nginx/conf/httpscert/www.xxx.com/dhparam.pem

7. 恢复 mysql 服务
docker run -id –restart=always –name=mysql -v /docker/mysql/data:/var/lib/mysql -v /docker/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=xxx –network docker-bridge-net -p 3306:3306 mysql:5.7
这里不打开防火墙端口,映射到主机 3306 端口,是为了备份脚本连接到数据库而已。
密码也不用改,如果通过 MYSQL_ROOT_PASSWORD 改了密码是不起作用的,原因是因为主机中的数据 /docker/mysql/data 映射到了新建的 mysql 容器中,数据库密码还是原来的,需要进入容器修改。

备份到dropbox

把tar cvpzf /backup/backup-$(date +%Y%m%d-%H%M).tgz /docker打包后上传dropbox出错,原因是因为太大了,所以把备份文件分卷压缩后上传,比较简单。

发表评论

电子邮件地址不会被公开。 必填项已用*标注