laravel:docker搭建lnmp+使用deployer部署

本地环境是mac。使用iTerm2+ohMyZsh
服务器环境是阿里云的ecs,绿色纯净centos7一只.

step1. 通过ssh登上服务器。配置免密登录。
step2. 服务器上安装docker和php(还有git、composer)。
step3. docker分别配置mysql、php、nginx。目标是能正常访问phpinfo。
step4. 本地安装deployer。
step5. git相关,创建一个laravel新项目。
step6. 配置deployer部署项目。目标是能正常访问laravel欢迎页以及正常使用laravel orm。

哇哦,看着6步,好像蛮少哦,坑超级多- - 一趟趟坑踩下来,快把自己蠢哭了。

step1. 「ssh登服务器」。

这一步所有操作都在本地,云服务器上不做任何改动。登进去后可输入exit回车退出,也可ctrl+D退出。

阿里云登上控制台,云服务器ECS查看示例有个公网ip,就这个公网ip

// 在本地命令行执行
ssh root@{你的云服务器公网 IP}

配置免密登录,在ECS管理面板中找到密钥对,点进去,创建密钥对。
『密钥对名称』,我填的是aen233,『创建类型』选择『自动新建密钥对』然后点击『确定』按钮:页面会弹出一个下载框下载 aen233.pem 文件,这个文件需要妥善保存,我把它放在~/.ssh下面了,配过git ssh的小伙伴应该都知道这个目录, 同时 SSH 命令要求密钥的访问权限必须是 600。

# 这个我忘记当时走这步没了,macOS好像木有需要改访问权限,如果是Linux就需要改权限。
chmod 600 ~/.ssh/aen233.pem

这时候可以免密登录了,但是要加 -i 参数

$ ssh root@{你的服务器公网 IP} -i ~/.ssh/aen233.pem

其中 -i 参数是告知 SSH 要用后面这个文件作为密钥登录。不出意外的话会看到询问是否信任该服务器,输入yes,登进。
为了不用每次登录都得加上 -i 参数, 编辑ssh的配置文件,如果没有的话,需要新建。

# 本地环境,不是服务器上的
vim ~/.ssh/config

macOS环境我用的atom编辑器。vim或atom都可以啦,总之编辑成下面这样

Host {你的云服务器公网 IP} 
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/aen233.pem

蓝后step1配置完成。

step2. 「服务器上安装docker和php」。

这一步操作都在云服务器上。

安装docker

Docker要求64位的系统且内核版本至少为3.10。
执行以下命令。

# 添加yum源。
yum install epel-release –y
yum clean all
yum list

# 安装并运行Docker。
yum install docker-io –y
systemctl start docker

# 检查安装结果。
docker info
安装php和git、composer

虽然docker也会创建php容器,但是服务器也需要php,而且必须要求php7.1.3+,因为deployer中的映射目录在服务器,不在docker中,这里就必须要git和composer。
如果php7.0及以下,执行laravel项目的时候,会报laravel require php7.1.3+ 这样的错误。
阿里云的centos7镜像中,php好像还是5.4还是5.6的版本,要先删掉,愚蠢如我,先下了7.0的版本,报错,又删了7.0的版本,安装了7.2的版本。
卸载php

yum list installed | grep php
yum remove php*

安装php7.2

# 首先获取rpm:
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm   
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm    

# 然后可以利用 sudo yum list php*查看目前都有php的什么版本了,可以发现从4-7.2的版本都有,7.2版本名为72w,因此安装该版本即可:
sudo yum -y install php72w

# 但安装完毕后,输入php -v发现并没有该命令,因为php72w只是安装了php最小的库,一些应用还未安装,因此安装一些拓展包即可:
yum -y install php72w-cli php72w-common php72w-devel php72w-mysql php72w-mbstring

然后是composer

// 下载composer
curl -sS https://getcomposer.org/installer | php

// 将composer.phar文件移动到bin目录以便全局使用composer命令
mv composer.phar /usr/local/bin/composer

// 切换国内源
composer config -g repo.packagist composer https://packagist.phpcomposer.com

step3. 「docker分别配置mysql、php、nginx」。

虽然有lnmp一键包,也有laradock很方便,还是打算分开开,好查错好维护。

先拉取3个镜像:这一步不分顺序,3个镜像拉取下来备用
// 获取mysql镜像
docker pull mysql:5.7

// 获取php7.2镜像
docker pull php:7.2-fpm

// 拉取nginx镜像
docker pull ngixn:1.12.2
创建3个容器:注意先后顺序,先mysql,再php,最后nginx
# 创建mysql容器
docker run -d -p 3306:3306 -v /var/docker/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name aen233_mysql mysql:5.7
/*  参数解释:
-p:端口映射,映射容器的3306. 例如:3307:3306:将容器的3306端口映射到主机的3307端口 
-v:/var/docker/mysql:/var/lib/mysql 将主机目录/var/docker/mysql挂载到容器的目录/var/lib/mysql,这个目录是mysql的数据目录,如果docker容器删除,数据还在。
-e:MYSQL_ROOT_PASSWORD=123456 初始化root用户的密码 
-it:运行交互式的容器,让docker运行的容器实现"对话"的能力 
-d:后台运行容器,并返回容器ID 
--name:命名容器
*/
--------------------------------------------------------
# 创建PHPfpm容器
docker run -d -v /var/www/html:/var/www/html -p 9000:9000 --link aen233_mysql:mysql --name aen233_phpfpm php:7.2-fpm
/*  参数解释:
-v 前面是主机的目录:映射容器的目录,这里需要和nginx容器中一致
--link:挂上msyql。因为php需挂载mysql,所以mysql需要在php之前。
*/
--------------------------------------------------------
# 创建nginx容器
docker run -d -p 80:80 --name aen233_nginx -v /var/www/html:/var/www/html -v /var/docker/nginx/conf.d:/etc/nginx/conf.d --link aen233_phpfpm:phpfpm --name aen233_nginx nginx:1.12.2
/*  参数解释:
-p:映射80端口
-v:/var/www/html:/var/www/html  这个目录和php容器中一致。
-v /var/docker/nginx/conf.d:/etc/nginx/conf.d  映射nginx配置目录,可以不用进docker容器(容器中就不需要安装vim等),直接在云服务器上修改nginx配置。
--name:容器名
--link:跟PHP关联,所以nginx容器创建要在php容器创建之后。
*/
接下来是配置docker中的mysql、php、nginx。以及测试目录映射是否生效。

接下来要进入docker容器了

配置mysql 允许远程登录

这样就可以在本地通过navicat、SequelPro这些数据库管理工具登进去了

# 进入容器 (可以用name也可以用容器id)
docker exec -it aen233_mysql bash

# 在容器内登陆mysql
root@74a6c7997285:/  mysql -uroot -p

# 为root分配权限,以便可以远程连接
mysql> grant all PRIVILEGES on *.* to root@'%' WITH GRANT OPTION;
mysql> exit;
配置php的扩展安装
# 进入到PHP容器 (可以用name也可以用容器id)
docker exec -it aen233_phpfpm /bin/bash

# php安装pdo_mysql,不走这一步,laravel会报 can not find driver 错误
docker-php-ext-install pdo_mysql(curl ...)

# 要安装php-redis的话,需要另外下载,执行下面这个命令就可以了,有问就no或者空格就好
pecl install redis && docker-php-ext-enable redis

# 安装后 php-m  发现就都有了哦

划重点:安装之后需要docker restart aen233_phpfpm。
划重点:安装之后需要docker restart aen233_phpfpm。
划重点:安装之后需要docker restart aen233_phpfpm。

配置Nginx容器,让他支持PHP

先在云服务器修改配置文件default.conf,如果没有改文件就先创建。

# 这个文件也可以本地写好,然后通过scp命令传到云服务器上
vi /var/docker/nginx/conf.d/default.conf

基础的default.conf如下

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    access_log  /var/log/nginx/host.access.log  main;

    location / {
       root   /var/www/html;
       index  index.php index.html index.htm;

       # 如果没有以下4行,laravel将只能访问首页,其他页面都是404
       try_files $uri $uri/ /index.php?$query_string;
       if (!-e $request_filename){  
           rewrite ^/(.*) /index.php last;  
       }
       # 如果没有以上4行,laravel将只能访问首页,其他页面都是404

    }

    #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           /var/www/html;
        index          index.php index.html;
        # 坑在这里,需将原有的127.0.0.1:9000替换成phpfpm:9000
        fastcgi_pass   phpfpm:9000;      
        # 坑在这里,需将原有的127.0.0.1:9000替换成phpfpm:9000
        fastcgi_index  index.php;
        # 下面这行也改了  中间的$document_root
        fastcgi_param  SCRIPT_FILENAME $document_root$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容器,敲一个命令“nginx -s reload”,退出即可。

# 进入Nginx容器:
docker exec -it aen233_nginx /bin/bash
# 重新加载Nginx
nginx -s reload
测试目录映射,访问phpinfo。

先在云服务器的主机 /var/www/html目录下新建index.php。

<?php
    echo phpinfo();

然后浏览器输入你的公网ip,不出意外就是phpinfo页面啦。
这里要重点去找pdo,查看它的mysql是否是enable状态。
如果你配php扩展执行了“docker-php-ext-install pdo_mysql”,但是没有重启php容器的话,你在容器中php -m,是能查看到pdo_mysql扩展的,但是在phpinfo中是pdo里是没有mysql的。laravel就会报can not find driver 错误。

step4. 「本地安装deployer」

deployer是安装在本地的。愚蠢如我,第一遍把它装在服务器上了

curl -LO https://deployer.org/deployer.phar

mv deployer.phar /usr/local/bin/dep

chmod +x /usr/local/bin/dep

这样就好了。执行dep 就能看到了

step5.「git相关,创建一个laravel新项目」

首先 要有git账号、然后要配好ssh key,再然后建立一个仓库、这个仓库可以是一个laravel新项目,随便写一个路由,控制器的方法中加一行 return User::all();用来测试laravel的orm。
我的项目叫iu。

step6. 「配置deployer部署项目」

创建部署脚本

在本地macOS中创建一个目录用于放置部署脚本:

我创建的目录在 ~/Sites/deploy-iu

$ cd ~/Sites/deploy-iu
$ dep init

dep init 命令用来创建一个部署脚本,会询问我们项目类型,我们是 Laravel 项目所以输入 1 然后回车;接下来询问 Repository 也就是我们代码仓库的地址,填入自己的 github 仓库地址即可。
Deployer 在当前目录下创建了一个名为 deploy.php 的文件。
我最终的deploy.php如下。

<?php
namespace Deployer;

require 'recipe/laravel.php';

set('repository', 'https://github.com/aen233/iu.git');
add('shared_files', []);
add('shared_dirs', []);
add('writable_dirs', []);
// 顺便把 composer 的 vendor 目录也加进来
add('copy_dirs', ['node_modules', 'vendor']);


host('111.22.3.4')
    ->user('root') // 使用 root 账号登录
    ->identityFile('~/.ssh/aen233.pem') // 指定登录密钥文件路径
    ->set('deploy_path', '/var/www/html/iu-deployer'); // 指定部署目录

// 定义一个上传 .artisan_env 文件的任务
desc('Upload .artisan_env file');
task('artisan_env:upload', function() {
    // 将本地的 .env 文件上传到代码目录的 .env
    upload('.artisan_env', '{{release_path}}/.env');
});

// 定义一个上传 .env 文件的任务
desc('Upload .env file');
task('env:upload', function() {
    // 将本地的 .env 文件上传到代码目录的 .env
    upload('.env', '{{release_path}}/.env');
});


// 在 deploy:vendors 之前调用 deploy:copy_dirs
before('deploy:vendors', 'deploy:copy_dirs');
before('deploy:symlink', 'artisan:migrate');

// 定义一个后置钩子,在 deploy:shared 之后执行 env:update 任务
after('deploy:shared', 'artisan_env:upload');
after('artisan:migrate', 'env:upload');
after('env:upload', 'artisan:config:cache');
after('artisan:config:cache', 'artisan:route:cache');
after('deploy:failed', 'deploy:unlock');

定义了两个上传任务,artisan_env:upload和env:upload,是因为执行migrate时,.env中的DB_HOST=127.0.0.1,但是执行migrate之后,.env的DB_HOST=mysql。
否则laravel会报SQLSTATE[HY000] [2002] Connection refused错误。
deploy执行migrate任务时,是在云服务器上操作,但是访问laravel页面时,是docker中的nginx和php和mysql交流。每个docker运行的容器都是隔离的,这里的host应该填php容器link的mysql容器。

after('env:upload', 'artisan:config:cache');
在上传env后,要执行artisan:config:cache。

执行部署命令

蓝后 在 ~/Sites/deploy-iu执行:

dep deploy
如果deployer执行composer项目时报错:

Failed to download laravel/laravel from dist: The zip extension and unzip command are both missing, skipping.
The php.ini used by your command-line PHP is: /etc/php.ini

# 解决办法: 在服务器上
yum install zip unzip
蓝后需要修改下nginx配置

deployer会将current指向当前部署的代码目录。

# 将default.conf中的两处root 改成如下
 root   /var/www/html/iu-deployer/current/public;
访问页面,如果是提示没有权限。报错:

The stream or file "/var/www/html/iu/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied

# 解决办法:
chmod 777 -R storage/
在iu目录下,给storage 777权限

还会遇到的报错,can not find driver,说过了,php容器要有pdo_mysql扩展
SQLSTATE[HY000] [2002] Connection refused,也说过了,.env中的DB_HOST要修改成mysql的docker容器,就是php容器 link的名字。
我自己还遇到一个很想哭的问题,View [welcome] not found. 这个是因为一开始创建容器是,映射的目录是-v /var/nginx/www/html:/var/www/html,而deployer会把storage共享出来,deployer的配置文件可能就写死了/var/nginx/www/html,而nginx访问的目录是/var/www/html,所以就找不到了。后来我将服务器、php、nginx的映射目录都统一写成/var/www/html。就好了。

应该可以咯。
phpstorm code + commit + push。
iterm2 执行命令dep deploy。

自动就发布咯。

参考的教程主要有:
leo电商进阶教程 第8章
bestcyt 这篇centos下使用docker搭建lnmp
田勇这篇deployer 实战经验分享

谢谢谢谢谢~~~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容