| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- <?php
- namespace Proginn;
- use Exception;
- use Medoo\Medoo;
- use Proginn\Config;
- use Redis;
- class Start
- {
- const IP_LOCK_KEY = 'docker:ip:';
- /**
- * 数据库链接
- *
- * @var Medoo $connection
- *
- */
- protected static $connection;
- /**
- * 数据库链接
- *
- * @var Redis $redis
- *
- */
- protected static $redis;
- protected $startIP = 180936414; // 10.200.222.222
- protected $domainSuffix = '.test.proginn.com';
- protected $containersBasePath = '/workspace/containers/';
- public function __construct($argv)
- {
- // 防止git仓库有人改了文件权限,容器里面shell脚本无法执行
- system("sudo chmod +x " . ROOT_DIR . '/shell/*');
- $params = $this->parseArgs($argv);
- $action = $params['action'];
- $proginnBranch = $params['proginn-branch'] ?? 'master';
- $rooterBranch = $params['rooter-branch'] ?? 'master';
- $proginnFrontendBranch = $params['proginn-frontend-branch'] ?? 'master';
- $name = $params['name'];
- switch ($action) {
- case 'start':
- $this->start($name, $proginnBranch, $rooterBranch, $proginnFrontendBranch);
- break;
- case 'remove':
- $this->remove($name);
- break;
- case 'dev':
- $this->dev("dev");
- break;
- case 'nginx':
- $this->nginx($name, $proginnBranch, $rooterBranch, $proginnFrontendBranch);//同步nginx配置,不用每次都重新拉取
- break;
- default:
- echo "Usage: php index.php --action=start|remove --name=mydev --proginn-branch=dev --rooter-branch=dev --proginn-frontend-branch dev\n";
- break;
- }
- }
- public function dev($name)
- {
- $this->containersBasePath = '/workspace/projects/';
- if (preg_match('/[^a-zA-Z0-9_]+/', $name)) {
- echo "创建失败,容器名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- $db = $this->getConnection();
- $row = $db->get('sites', '*', [
- 'name' => $name,
- ]);
- if (!empty($row)) {
- echo "创建失败,容器:{$name}已经存在,请确认。\n";
- return;
- }
- $ip = $this->getIp();
- $ipv4 = long2ip($ip);
- $domain = $name;
- $fullDomain = $name . $this->domainSuffix;
- $this->getConnection()->query('start transaction');
- try {
- $id = $this->getConnection()->insert('sites', [
- 'proginn_branch' => "dev",
- 'domain' => $domain,
- 'ip' => $ip,
- 'ipv4' => $ipv4,
- 'created_at' => time(),
- 'name' => $name,
- 'rooter_branch' => "dev",
- 'proginn_frontend_branch' => "dev",
- 'full_domain' => $fullDomain,
- ]);
- if (!$id) {
- throw new Exception('创建数据库记录失败');
- }
- // 容器存储目录
- $directory = $this->containersBasePath;
- // 创建日志相关目录
- if(!file_exists($directory . '/log/pm2')) mkdir($directory . '/log/pm2', 0777, true); //
- if(!file_exists($directory . '/log/proginn_cache')) mkdir($directory . '/log/proginn_cache', 0777, true); //
- // 配置存放目录
- if(!file_exists($directory . '/config')) mkdir($directory . '/config', 0777, true); //
- // yml 文件
- $template = file_get_contents(ROOT_DIR . '/dockerfile/template.yml');
- $template = str_replace('containers/<containerName>', "project", $template);
- $template = str_replace('<ip>', $ipv4, $template);
- $template = str_replace('<proginn-branch>', "dev", $template);
- $template = str_replace('<rooter-branch>', "dev", $template);
- $template = str_replace('<proginn-frontend-branch>', "dev", $template);
- $template = str_replace('<domain>', $domain, $template);
- $template = str_replace('<fullDomain>', $fullDomain, $template);
- $template = str_replace('<containerName>', "dev", $template);
- file_put_contents($directory . 'config/docker.yml', $template);
- // nginx 配置
- $proxy = file_get_contents(ROOT_DIR . '/config/nginx/template/proxy.nginx.conf');
- $proxy = str_replace('{{domain}}', $domain, $proxy);
- $proxy = str_replace('{{ip}}', $ipv4, $proxy);
- file_put_contents("/workspace/commonContainers/nginx/conf.d/{$name}.conf", $proxy);
- $proginn = file_get_contents(ROOT_DIR . '/config/nginx/template/proginn.nginx.conf');
- $proginn = str_replace('{{domain}}', $domain, $proginn);
- $proginn = str_replace('{{ip}}', $ipv4, $proginn);
- file_put_contents("{$directory}/config/nginx.conf", $proginn);
- $log = file_get_contents(ROOT_DIR . '/config/logrotate/log.conf');
- $log = str_replace('{{containerName}}', $name, $log);
- file_put_contents($directory . 'config/logrotate.conf', $log);
- system("sudo cp -f {$directory}config/logrotate.conf /etc/logrotate.d/{$name}");
- // 写入项目变量 Found orphan containers
- file_put_contents($directory . 'config/.env', "COMPOSE_PROJECT_NAME={$name}");
- // 启动容器
- system("docker-compose -p {$name} -f {$directory}config/docker.yml up -d");
- // 重载Nginx
- system("docker exec nginx nginx -s reload");
- $this->getConnection()->query('commit');
- } catch (\Throwable $e) {
- echo "exception:" . $e->__toString() . "\n";
- $this->getConnection()->query('rollback');
- if (file_exists($directory . 'config/docker.yml')) {
- system("docker-compose -p {$name} -f {$directory}config/docker.yml rm -s -f");
- }
- $redis = $this->getRedis();
- $lockKey = static::IP_LOCK_KEY . $ip;
- $redis->del($lockKey);
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- system("sudo rm -rf {$directory}");
- system("rm -f /workspace/commonContainers/nginx/conf.d/{$name}.conf");
- system("docker exec nginx nginx -s reload");
- system("sudo rm -f /etc/logrotate.d/{$name}");
- }
- }
- public function nginx($name, $proginnBranch, $rooterBranch, $proginnFrontendBranch)
- {
- if (preg_match('/[^a-zA-Z0-9_]+/', $name)) {
- echo "创建失败,容器名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $proginnBranch)) {
- echo "创建失败,proginn分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $rooterBranch)) {
- echo "创建失败,rooter分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $proginnFrontendBranch)) {
- echo "创建失败,proginn-frontend分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- $db = $this->getConnection();
- $row = $db->get('sites', '*', [
- 'name' => $name,
- ]);
- if (empty($row)) {
- echo "获取失败,容器:{$name}不存在,请确认。\n";
- return;
- }
- $ip = $this->getIp();
- $ipv4 = long2ip($ip);
- $domain = $name;
- $this->getConnection()->query('start transaction');
- try {
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- // nginx 配置
- $proginn = file_get_contents(ROOT_DIR . '/config/nginx/template/proginn.nginx.conf');
- $proginn = str_replace('{{domain}}', $domain, $proginn);
- $proginn = str_replace('{{ip}}', $ipv4, $proginn);
- file_put_contents("{$directory}/config/nginx.conf", $proginn);
- // 重载Nginx
- system("docker exec nginx nginx -s reload");
- $this->getConnection()->query('commit');
- } catch (\Throwable $e) {
- echo "exception:" . $e->__toString() . "\n";
- $this->getConnection()->query('rollback');
- }
- }
- public function start($name, $proginnBranch, $rooterBranch, $proginnFrontendBranch)
- {
- if (preg_match('/[^a-zA-Z0-9_]+/', $name)) {
- echo "创建失败,容器名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $proginnBranch)) {
- echo "创建失败,proginn分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $rooterBranch)) {
- echo "创建失败,rooter分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- if (preg_match('/[^a-zA-Z0-9_]+/', $proginnFrontendBranch)) {
- echo "创建失败,proginn-frontend分支名:{$name}只能字母、数字及下划线组成。\n";
- return;
- }
- $db = $this->getConnection();
- $row = $db->get('sites', '*', [
- 'name' => $name,
- ]);
- if (!empty($row)) {
- echo "创建失败,容器:{$name}已经存在,请确认。\n";
- return;
- }
- $ip = $this->getIp();
- $ipv4 = long2ip($ip);
- $domain = $name;
- $fullDomain = $name . $this->domainSuffix;
- $this->getConnection()->query('start transaction');
- try {
- $id = $this->getConnection()->insert('sites', [
- 'proginn_branch' => $proginnBranch,
- 'domain' => $domain,
- 'ip' => $ip,
- 'ipv4' => $ipv4,
- 'created_at' => time(),
- 'name' => $name,
- 'rooter_branch' => $rooterBranch,
- 'proginn_frontend_branch' => $proginnFrontendBranch,
- 'full_domain' => $fullDomain,
- ]);
- if (!$id) {
- throw new Exception('创建数据库记录失败');
- }
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- // 创建容器存储目录
- mkdir($directory, 0777, true);
- // 拷贝项目
- system("cp -Rf /workspace/projects/proginn {$directory}");
- system("cp -Rf /workspace/projects/proginn-frontend {$directory}");
- system("cp -Rf /workspace/projects/boss {$directory}");
- system("cp -Rf /workspace/projects/festival {$directory}");
- system("cp -Rf /workspace/projects/docker-test {$directory}");
- system("cp -Rf /workspace/projects/proginn-user {$directory}");
- system("cp -Rf /workspace/projects/proginn-bituni {$directory}");
- // 创建日志相关目录
- mkdir($directory . '/log/pm2', 0777, true); //
- mkdir($directory . '/log/proginn_cache', 0777, true); //
- // 配置存放目录
- mkdir($directory . '/config', 0777, true); //
- // yml 文件
- $template = file_get_contents(ROOT_DIR . '/dockerfile/template.yml');
- $template = str_replace('<containerName>', $name, $template);
- $template = str_replace('<ip>', $ipv4, $template);
- $template = str_replace('<proginn-branch>', $proginnBranch, $template);
- $template = str_replace('<rooter-branch>', $rooterBranch, $template);
- $template = str_replace('<proginn-frontend-branch>', $proginnFrontendBranch, $template);
- $template = str_replace('<domain>', $domain, $template);
- $template = str_replace('<fullDomain>', $fullDomain, $template);
- file_put_contents($directory . '/config/docker.yml', $template);
- // nginx 配置
- $proxy = file_get_contents(ROOT_DIR . '/config/nginx/template/proxy.nginx.conf');
- $proxy = str_replace('{{domain}}', $domain, $proxy);
- $proxy = str_replace('{{ip}}', $ipv4, $proxy);
- file_put_contents("/workspace/commonContainers/nginx/conf.d/{$name}.conf", $proxy);
- $proginn = file_get_contents(ROOT_DIR . '/config/nginx/template/proginn.nginx.conf');
- $proginn = str_replace('{{domain}}', $domain, $proginn);
- $proginn = str_replace('{{ip}}', $ipv4, $proginn);
- file_put_contents("{$directory}/config/nginx.conf", $proginn);
- $log = file_get_contents(ROOT_DIR . '/config/logrotate/log.conf');
- $log = str_replace('{{containerName}}', $name, $log);
- file_put_contents($directory . '/config/logrotate.conf', $log);
- system("sudo cp -f {$directory}/config/logrotate.conf /etc/logrotate.d/{$name}");
- // 写入项目变量 Found orphan containers
- file_put_contents($directory . '/config/.env', "COMPOSE_PROJECT_NAME={$name}");
- // 启动容器
- system("docker-compose -p {$name} -f {$directory}/config/docker.yml up -d");
- // 重载Nginx
- system("docker exec nginx nginx -s reload");
- $this->getConnection()->query('commit');
- } catch (\Throwable $e) {
- echo "exception:" . $e->__toString() . "\n";
- $this->getConnection()->query('rollback');
- if (file_exists($directory . '/config/docker.yml')) {
- system("docker-compose -p {$name} -f {$directory}/config/docker.yml rm -s -f");
- }
- $redis = $this->getRedis();
- $lockKey = static::IP_LOCK_KEY . $ip;
- $redis->del($lockKey);
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- system("sudo rm -rf {$directory}");
- system("rm -f /workspace/commonContainers/nginx/conf.d/{$name}.conf");
- system("docker exec nginx nginx -s reload");
- system("sudo rm -f /etc/logrotate.d/{$name}");
- }
- }
- protected function remove($name)
- {
- $db = $this->getConnection();
- $row = $db->get('sites', '*', [
- 'name' => $name,
- ]);
- if (empty($row)) {
- echo "删除失败,容器:{$name}不存在,请确认。\n";
- return;
- }
- $this->getConnection()->query('start transaction');
- try {
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- $db->delete('sites', [
- 'name' => $name,
- ]);
- if (file_exists($directory . '/config/docker.yml')) {
- system("docker-compose -p {$name} -f {$directory}/config/docker.yml rm -s -f");
- }
- // 容器存储目录
- $directory = $this->containersBasePath . $name;
- system("sudo rm -rf {$directory}");
- system("rm -f /workspace/commonContainers/nginx/conf.d/{$name}.conf");
- system("docker exec nginx nginx -s reload");
- $redis = $this->getRedis();
- $lockKey = static::IP_LOCK_KEY . $row['ip'];
- $redis->del($lockKey);
- $this->getConnection()->query('commit');
- } catch (\Throwable $e) {
- echo "exception:" . $e->__toString() . "\n";
- $this->getConnection()->query('rollback');
- }
- }
- protected function getIp()
- {
- $ip = $this->startIP;
- $redis = $this->getRedis();
- while (true) {
- $ip++;
- $lockKey = static::IP_LOCK_KEY . $ip;
- $lock = $redis->setnx($lockKey, $ip);
- if ($lock) {
- break;
- }
- }
- return $ip;
- }
- protected function parseArgs($argv)
- {
- unset($argv[0]);
- $params = [];
- foreach ($argv as $i => $arg) {
- $arg = explode('=', $arg);
- $key = trim($arg[0], "-");
- $val = $arg[1] ?? true;
- $params[$key] = $val;
- }
- return $params;
- }
- protected function getRedis()
- {
- if (static::$redis === null) {
- static::$redis = new Redis();
- static::$redis->connect(Config::REDIS_HOST, Config::REDIS_PORT, 3);
- static::$redis->auth(Config::REDIS_PASS);
- }
- return static::$redis;
- }
- /**
- * @return Medoo
- */
- protected function getConnection()
- {
- if (static::$connection === null) {
- static::$connection = new Medoo([
- 'database_type' => 'mysql',
- 'database_name' => Config::DB_NAME,
- 'server' => Config::DB_HOST,
- 'username' => Config::DB_USER,
- 'password' => Config::DB_PASS,
- 'charset' => Config::DB_CHAR,
- 'port' => Config::DB_PORT,
- 'prefix' => '',
- 'logging' => true,
- ]);
- }
- return static::$connection;
- }
- }
|