PHP报错Call to undefined function解决
前言
运行PHP代码,突然报错:"Call to undefined function xxx()"?这个错太常见了,一般就是扩展没装或者文件没引入。本文讲怎么排查和解决。
一、报错长啥样
Fatal error: Uncaught Error: Call to undefined function mysql_connect() in xxx.php on line 5
意思:你调用了一个不存在的函数。
二、常见原因
原因1:PHP扩展没装
比如用了 mysqli_connect(),但没装mysqli扩展。
或者用了 gd库 的函数,但没装gd。
原因2:文件没引入
你自己写的函数,忘了include/require文件。
原因3:函数名写错了
拼写错了,比如 str_lower 写成 strlower。
原因4:PHP版本不对
低版本PHP没有高版本才有的函数。
三、排查步骤
第一步:看是哪个函数报错
报错信息里会告诉你函数名:
Call to undefined function curl_init()
这里就是 curl_init() 函数没找到。
第二步:判断是内置函数还是自己写的
- 内置函数:PHP自带的,比如
curl_init、mysqli_connect - 自己写的:你在别的文件里定义的
第三步:如果是内置函数,查扩展装了没
php -m | grep curl
看看curl扩展装了没。
或者写个phpinfo:
<?php
phpinfo();
?>
搜这个函数名对应的扩展,看有没有。
四、安装扩展
例子1:装curl扩展
# CentOS
yum install php-curl
# Ubuntu
apt install php-curl
例子2:装mysqli扩展
yum install php-mysqli
例子3:装gd库
yum install php-gd
装完重启
systemctl restart php-fpm
五、如果是自己写的函数
检查文件引入
<?php
// 引入函数文件
require 'functions.php';
// 调用
my_function();
检查函数名对不对
// functions.php里定义的
function my_function() {
// ...
}
调用的时候名字要一模一样。
检查命名空间
如果用了命名空间,要注意:
<?php
namespace App;
// 调用别的命名空间的函数
\OtherNamespace\my_function();
六、常见函数和对应扩展
| 函数 | 需要的扩展 |
|---|---|
| mysqli_connect | mysqli |
| curl_init | curl |
| imagecreate | gd |
| mb_strlen | mbstring |
| openssl_encrypt | openssl |
| pdo连接 | pdo_mysql |
| json_encode | json(默认有) |
| file_get_contents | 不需要(默认有) |
七、常见坑
坑1:mysql函数被废弃了
PHP7以后,mysql_* 函数都没了,要用mysqli或者PDO。
Call to undefined function mysql_connect()
解决: 换成mysqli或者PDO。
坑2:CLI和FPM装的扩展不一样
命令行里装了,网页上没有。
原因: CLI和FPM用不同的php.ini。
解决: 看phpinfo里的配置,装到对应的PHP版本里。
坑3:装了扩展没重启
装完忘了重启php-fpm。
解决:
systemctl restart php-fpm
坑4:函数名大小写
PHP函数名不区分大小写,但自己写的类方法区分。
坑5:Composer自动加载没生效
用了Composer的库,但没 vendor/autoload.php。
require 'vendor/autoload.php';
八、快速排查
第一步:看报错的函数名
Call to undefined function xxx()
第二步:查扩展
php -m | grep 扩展名
第三步:没装就装
yum install php-扩展名
第四步:重启
systemctl restart php-fpm
九、常用扩展安装
一次性装常用扩展
yum install php-mysqli php-curl php-gd php-mbstring php-xml php-json
Ubuntu
apt install php-mysqli php-curl php-gd php-mbstring php-xml
总结
记住:
- 报错会告诉你是哪个函数没找到
- 内置函数就查扩展装了没
- 自己写的就查文件引入了没
- 装完扩展要重启php-fpm
- mysql_* 函数PHP7没了,换mysqli
排查流程:
看报错函数名 → 判断是内置还是自己写的 → 内置查扩展 → 自己写的查引入 → 解决
遇到问题加QQ23979811 协助处理
PHP mysqli连接MySQL,完整示例代码
前言
PHP连MySQL用mysqli扩展,比mysql扩展好用,支持预处理、事务等。本文写个完整的连接和增删改查示例。
一、连接数据库
面向过程写法
<?php
$host = '127.0.0.1';
$user = 'root';
$pass = '123456';
$dbname = 'test';
$port = 3306;
// 连接
$conn = mysqli_connect($host, $user, $pass, $dbname, $port);
// 检查连接
if (!$conn) {
die('连接失败: ' . mysqli_connect_error());
}
echo '连接成功';
面向对象写法
<?php
$conn = new mysqli('127.0.0.1', 'root', '123456', 'test', 3306);
if ($conn->connect_error) {
die('连接失败: ' . $conn->connect_error);
}
echo '连接成功';
二、设置字符集
mysqli_set_charset($conn, 'utf8mb4');
// 或者
$conn->set_charset('utf8mb4');
注意: 一定要设utf8mb4,不然中文表情存不进去。
三、查询数据(SELECT)
面向过程
$sql = "SELECT id, name, age FROM users WHERE status = 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
while ($row = mysqli_fetch_assoc($result)) {
echo "ID: " . $row['id'] . " 姓名: " . $row['name'] . "<br>";
}
} else {
echo "没有数据";
}
面向对象
$sql = "SELECT id, name, age FROM users WHERE status = 1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row['id'] . " 姓名: " . $row['name'] . "<br>";
}
}
取所有数据为数组
$list = [];
while ($row = mysqli_fetch_assoc($result)) {
$list[] = $row;
}
print_r($list);
四、插入数据(INSERT)
直接写SQL
$name = '张三';
$age = 20;
$sql = "INSERT INTO users (name, age) VALUES ('$name', $age)";
if (mysqli_query($conn, $sql)) {
echo "插入成功,ID: " . mysqli_insert_id($conn);
} else {
echo "插入失败: " . mysqli_error($conn);
}
预处理(防SQL注入,推荐)
$stmt = mysqli_prepare($conn, "INSERT INTO users (name, age) VALUES (?, ?)");
mysqli_stmt_bind_param($stmt, 'si', $name, $age);
// 'si' 表示:string, int
$name = '李四';
$age = 25;
if (mysqli_stmt_execute($stmt)) {
echo "插入成功,ID: " . mysqli_insert_id($conn);
} else {
echo "失败: " . mysqli_error($conn);
}
五、更新数据(UPDATE)
$id = 1;
$name = '王五';
$sql = "UPDATE users SET name = '$name' WHERE id = $id";
if (mysqli_query($conn, $sql)) {
echo "更新成功,影响行数: " . mysqli_affected_rows($conn);
}
六、删除数据(DELETE)
$id = 1;
$sql = "DELETE FROM users WHERE id = $id";
if (mysqli_query($conn, $sql)) {
echo "删除成功";
}
七、关闭连接
mysqli_close($conn);
// 或者
$conn->close();
八、完整示例封装
<?php
class DB
{
private $conn;
public function __construct()
{
$this->conn = new mysqli('127.0.0.1', 'root', '123456', 'test', 3306);
if ($this->conn->connect_error) {
die('连接失败');
}
$this->conn->set_charset('utf8mb4');
}
// 查询多行
public function queryAll($sql)
{
$result = $this->conn->query($sql);
$list = [];
while ($row = $result->fetch_assoc()) {
$list[] = $row;
}
return $list;
}
// 查询单行
public function queryOne($sql)
{
$result = $this->conn->query($sql);
return $result->fetch_assoc();
}
// 关闭
public function __destruct()
{
$this->conn->close();
}
}
// 使用
$db = new DB();
$users = $db->queryAll("SELECT * FROM users");
print_r($users);
九、常见坑
坑1:SQL注入
直接拼接变量到SQL里,有注入风险。
解决: 用预处理语句(?占位符)。
坑2:中文乱码
忘了设字符集。
解决: 连接后立刻 set_charset('utf8mb4')。
坑3:只取一行
用 mysqli_fetch_assoc 循环多次才取完。
注意: 这个函数每次只取一行,要循环。
坑4:连接失败没报错
生产环境关了错误显示。
解决: 手动检查 mysqli_connect_error()。
坑5:忘了关连接
频繁连接不关,占资源。
解决: 用完就关,或者用单例。
总结
记住:
mysqli_connect连接数据库set_charset('utf8mb4')设字符集mysqli_query执行SQLmysqli_fetch_assoc取数据- 防注入用预处理(?占位符)
- 用完
mysqli_close关连接
最常用:
$conn = mysqli_connect('127.0.0.1', 'root', '123456', 'test', 3306);
mysqli_set_charset($conn, 'utf8mb4');
遇到问题加QQ23979811 协助处理
PHP上传文件大小限制,修改php.ini
前言
上传个大点的文件,提示"文件过大"或者直接报错?那是PHP上传限制太小了。本文讲怎么改php.ini调大上传限制。
一、默认限制多大
PHP默认上传限制一般是:
upload_max_filesize= 2Mpost_max_size= 8M
传个10M的文件就不行了。
二、要改哪几个参数
1. upload_max_filesize
单个文件最大大小:
upload_max_filesize = 100M
2. post_max_size
整个POST请求最大大小:
post_max_size = 100M
注意: post_max_size要 >= upload_max_filesize。
3. memory_limit
脚本可用内存:
memory_limit = 128M
要比post_max_size大。
4. max_execution_time
脚本最大执行时间(秒):
max_execution_time = 300
传大文件要久一点,设长点。
5. max_input_time
接收数据最大时间(秒):
max_input_time = 300
三、找php.ini
php --ini
或者写个phpinfo:
<?php
phpinfo();
?>
看Loaded Configuration File。
四、修改php.ini
改成100M上传
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M
max_execution_time = 300
max_input_time = 300
改成50M上传
upload_max_filesize = 50M
post_max_size = 50M
memory_limit = 64M
五、改完重启
PHP-FPM
systemctl restart php-fpm
Apache
systemctl restart httpd
六、验证
写个phpinfo,看这几个参数改了没:
<?php
phpinfo();
?>
搜 upload_max_filesize,看是不是改过来了。
七、Nginx也要改
光改PHP不够,Nginx也有限制。
Nginx配置
client_max_body_size 100M;
改完重载
nginx -t
nginx -s reload
八、常见坑
坑1:改了php.ini不生效
改的不是实际加载的那个。
解决: 用phpinfo看实际加载的是哪个。
坑2:只改了upload_max_filesize
post_max_size没改,还是不行。
注意: 两个都要改,post_max_size >= upload_max_filesize。
坑3:Nginx挡了
PHP改了,Nginx的client_max_body_size没改,还是413错误。
解决: Nginx也改。
坑4:内存不够
Allowed memory size of ... bytes exhausted
解决: 加大memory_limit。
坑5:上传超时
大文件传一半就断了。
解决: 加大max_execution_time和max_input_time。
坑6:.htaccess里覆盖了
有些主机在.htaccess里设了php_value。
检查: 看看.htaccess里有没有。
九、快速排查
上传报错
- 先看PHP的upload_max_filesize够不够
- 再看post_max_size够不够
- 再看Nginx的client_max_body_size够不够
- 再看memory_limit够不够
十、推荐配置
一般网站(20M上传)
upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 64M
文件站(100M上传)
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M
max_execution_time = 300
max_input_time = 300
Nginx对应
client_max_body_size 100M;
总结
记住:
- 改三个参数:upload_max_filesize、post_max_size、memory_limit
- post_max_size >= upload_max_filesize
- Nginx也要改client_max_body_size
- 改完重启php-fpm和reload nginx
- 大文件要加大超时时间
最常用:
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 128M
遇到问题加QQ23979811 协助处理
PHP开启错误显示,php.ini配置修改
前言
PHP报错了,页面白屏或者500,啥也不显示,不知道哪错了?开了错误显示就能看到具体错误了。本文讲怎么改php.ini开启错误显示。
一、为什么不显示错误
生产环境为了安全,默认不显示错误,防止暴露敏感信息(路径、数据库密码等)。
但开发的时候就不方便了,啥也看不到。
二、找到php.ini
找php.ini位置
php --ini
输出:
Loaded Configuration File: /etc/php.ini
或者:
/etc/php/7.4/cli/php.ini
注意:CLI和FPM的php.ini可能不一样。
看当前加载的是哪个
写个phpinfo:
<?php
phpinfo();
?>
浏览器访问,看Loaded Configuration File。
三、修改php.ini
1. 显示错误
display_errors = On
2. 报错级别
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
或者全开:
error_reporting = E_ALL
3. 错误日志
log_errors = On
error_log = /var/log/php_errors.log
4. 显示启动错误
display_startup_errors = On
四、改完重启
PHP-FPM
systemctl restart php-fpm
或者:
systemctl reload php-fpm
Apache
systemctl restart httpd
五、代码里临时开启
不想改php.ini,在代码开头加:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
或者:
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
六、常见错误类型
E_ALL
所有错误和警告。
E_ERROR
致命运行错误,脚本停止。
E_WARNING
运行时警告,脚本继续。
E_NOTICE
运行时注意,比如未定义变量。
七、常见坑
坑1:改了php.ini不生效
改的不是实际加载的那个php.ini。
解决: 用 php --ini 看实际加载的是哪个。
坑2:FPM和CLI的php.ini不一样
命令行改了,网页上不生效。
原因: CLI和FPM用不同的php.ini。
解决: 改FPM的那个,比如 /etc/php/7.4/fpm/php.ini。
坑3:页面白屏
可能是语法错误,php.ini都没加载起来。
检查: 看PHP错误日志。
坑4:开了错误显示有安全风险
生产环境不能开!
注意: 排查完一定要改回去。
坑5:.htaccess里覆盖了
有些主机在.htaccess里设了php_flag。
检查: 看看.htaccess里有没有。
八、生产环境配置
生产环境不要开display_errors,但要开日志:
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED
九、查看错误日志
PHP错误日志
tail -f /var/log/php_errors.log
Nginx错误日志
tail -f /var/log/nginx/error.log
Apache错误日志
tail -f /var/log/httpd/error_log
十、快速排查
第一步:代码里临时开
ini_set('display_errors', 1);
error_reporting(E_ALL);
第二步:看具体报错
刷新页面,看报什么错。
第三步:解决完删掉
改完了把代码里的ini_set删掉,或者改回生产配置。
总结
记住:
display_errors = On显示错误error_reporting = E_ALL显示所有错误- 改完重启php-fpm
- 生产环境关掉display_errors,开log_errors
- 代码里可以用ini_set临时开
开发环境推荐:
display_errors = On
error_reporting = E_ALL
log_errors = On
生产环境推荐:
display_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_NOTICE
遇到问题加QQ23979811 协助处理
Composer安装依赖超时,国内镜像源配置
前言
composer install 装依赖,半天没反应,最后超时失败?那是因为默认的源在国外,国内访问慢。换个国内镜像就快了。
一、为什么会超时
Composer默认从 packagist.org 下载包,服务器在国外,国内访问慢,经常超时。
换个国内镜像源,速度飞快。
二、常用国内镜像
1. 阿里云镜像
https://mirrors.aliyun.com/composer/
2. 腾讯云镜像
https://mirrors.tencent.com/composer/
3. 华为云镜像
https://mirrors.huaweicloud.com/repository/php/
4. 豆瓣镜像(老了,不推荐)
https://packagist.phpcomposer.com
三、全局配置镜像
方法1:命令行配置
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
方法2:改config文件
编辑 ~/.composer/config.json:
{
"repositories": {
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
}
}
查看当前镜像
composer config -g repo.packagist
四、项目单独配置
在项目根目录的 composer.json 里加:
{
"repositories": {
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
}
}
或者用命令:
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
五、临时使用镜像
不想改全局配置,临时用一次:
composer install --prefer-dist -vvv --repository-url=https://mirrors.aliyun.com/composer/
六、其他常用配置
1. 禁用github接口调用
有时候github的API调用会卡住,禁用掉:
composer config -g github-protocols https
2. 国内composer下载地址
安装composer的时候也慢,用国内下载:
php -r "copy('https://mirrors.aliyun.com/composer/composer.phar', 'composer.phar');"
3. 查看配置
composer config -g --list
七、安装依赖
安装
composer install
更新
composer update
加-v看详细过程
composer install -vvv
八、常见坑
坑1:装了还是慢
缓存没清。
解决:
composer clear-cache
坑2:报SSL错误
SSL certificate problem
解决: 关掉SSL验证(不推荐临时用):
composer config -g secure-http false
坑3:提示文件权限不够
Failed to download ...
解决: 目录权限不对。
chmod -R 777 vendor
chmod -R 777 composer.json
坑4:内存不够
Allowed memory size of ... bytes exhausted
解决: 加大内存:
php -d memory_limit=-1 /usr/local/bin/composer install
坑5:镜像也挂了
阿里云镜像有时候也抽风。
解决: 换一个镜像,比如腾讯云的。
九、验证镜像生效
查看当前镜像源
composer config -g repo.packagist
输出应该是你设的阿里云地址。
装个小包试试速度
composer require monolog/monolog
看下载速度快不快。
十、推荐配置
一键配置阿里云镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
清缓存
composer clear-cache
安装
composer install
总结
记住:
- 慢就换国内镜像,阿里云的最稳
- 全局配置:
composer config -g repo.packagist composer 地址 - 不行就清缓存:
composer clear-cache - 换镜像:阿里云、腾讯云、华为云
- 临时用:加
--repository-url=地址
最常用:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
遇到问题加QQ23979811 协助处理
ThinkPHP6 500报错,开启错误日志查看原因
前言
ThinkPHP6网站突然500报错,页面啥也不显示,不知道哪错了?本文讲怎么开启错误显示和日志,快速定位问题。
一、为什么500不显示错误
生产环境为了安全,关闭了错误显示,直接返回500,不显示具体错误信息。
这是对的,不然用户能看到你的代码路径、数据库密码等敏感信息。
但排查问题就不方便了。
二、临时开启错误显示
修改 .env 文件
项目根目录下有个 .env 文件:
APP_DEBUG = true
把 APP_DEBUG 改成 true。
刷新页面,就能看到具体错误了。
注意
排查完记得改回 false! 生产环境不能开debug。
三、开启日志记录
就算不开debug,错误也会记录到日志文件里。
日志配置
config/log.php 文件:
return [
// 默认日志通道
'default' => 'file',
// 日志通道列表
'channels' => [
'file' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => '',
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => [],
// 最大日志文件数量
'max_files' => 30,
],
],
];
日志位置
默认在 runtime/log/ 目录下。
按日期分目录:
runtime/log/
├── 2026-10/
│ ├── 08.log
│ ├── 07.log
│ └── 06.log
└── 2026-09/
└── ...
查看今天的错误
tail -f runtime/log/2026-10/08.log
四、常见500错误排查
1. 目录权限问题
runtime目录没权限写:
Permission denied
解决:
chmod -R 755 runtime
chown -R www:www runtime
2. 缺少扩展
Call to undefined function xxx()
解决: 装对应的PHP扩展。
3. 数据库连接失败
SQLSTATE[HY000] [1045] Access denied
检查: 数据库配置对不对。
.env 或 config/database.php:
'hostname' => '127.0.0.1',
'database' => '数据库名',
'username' => '用户名',
'password' => '密码',
4. 路由错误
Route not found
检查: 路由配置对不对。
5. 模板找不到
template not exists
检查: 模板文件路径对不对。
五、手动写日志
代码里可以手动写日志:
// 记录错误
Trace::error('这是一个错误信息');
// 记录警告
Trace::warning('这是一个警告');
// 记录信息
Trace::info('这是一个信息');
或者用助手函数:
trace('这是调试信息', 'debug');
六、查看PHP错误日志
除了ThinkPHP的日志,PHP本身也有错误日志。
查看PHP错误日志位置
php --ini | grep error_log
Nginx错误日志
tail -f /var/log/nginx/error.log
七、常见排查步骤
第一步:开debug看具体错误
改 .env:
APP_DEBUG = true
刷新页面,看具体报什么错。
第二步:看ThinkPHP日志
tail -f runtime/log/2026-10/08.log
第三步:看Nginx错误日志
tail -f /var/log/nginx/error.log
第四步:看PHP错误日志
tail -f /var/log/php-fpm/error.log
第五步:解决完改回debug
改完 .env:
APP_DEBUG = false
八、常见坑
坑1:开了debug还是不显示
缓存没清。
解决: 删除runtime目录下的缓存:
rm -rf runtime/cache/*
坑2:日志目录没权限
stream_socket_client(): unable to connect
runtime目录没写权限。
解决:
chmod -R 755 runtime
坑3:生产环境开着debug
危险!用户能看到你的敏感信息。
解决: 排查完立刻改回 APP_DEBUG = false。
坑4:日志太大占磁盘
日志越积越多,磁盘满了。
解决: 设 max_files,自动删除旧日志:
'max_files' => 30,
坑5:502和500搞混
- 500:PHP代码错误
- 502:PHP-FPM挂了
区分: 看Nginx错误日志。
总结
记住:
- 改
.env的APP_DEBUG = true临时看错误 - 生产环境必须改回
false - 日志在
runtime/log/目录 - 排查完记得清缓存
- 500是PHP代码问题,502是FPM问题
排查流程:
开debug → 看具体报错 → 看ThinkPHP日志 → 看Nginx日志 → 解决问题 → 关debug
遇到问题加QQ23979811 协助处理
PHP FPM进程过多导致服务器卡顿优化
前言
PHP FPM进程太多,把服务器内存吃满,网站卡顿甚至502?本文讲怎么优化PHP FPM进程数。
一、为什么FPM进程多会卡
PHP FPM每处理一个请求,就开一个进程。
进程开多了:
- 内存占满
- CPU切换不过来
- 服务器卡顿
- 甚至OOM被杀
二、查看当前进程数
查看PHP FPM进程
ps aux | grep php-fpm
数一下有多少个进程。
看每个进程占多少内存
ps aux | grep php-fpm | awk '{print $6/1024 "MB"}'
算一下总内存
ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/1024 "MB"}'
三、FPM配置文件在哪
CentOS
/etc/php-fpm.d/www.conf
或者:
/etc/php/7.4/fpm/pool.d/www.conf
Ubuntu
/etc/php/7.4/fpm/pool.d/www.conf
四、进程管理模式
PHP FPM有三种进程管理模式:
1. static(静态)
固定进程数,启动就开这么多。
pm = static
pm.max_children = 50
2. dynamic(动态)
默认模式,按需开进程。
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
3. ondemand
没人访问的时候不开进程,来了请求才开。
pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s
五、怎么算合适的进程数
公式
pm.max_children = 可用内存 / 每个进程平均内存
例子
- 服务器2G内存
- 系统和其他服务占1G
- 剩下1G给PHP
- 每个PHP进程平均占40M
pm.max_children = 1024 / 40 ≈ 25
所以设25个进程差不多。
别设太大
设太大了,内存不够用,就会OOM。
六、推荐配置
小服务器(1G内存)
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
中服务器(2-4G内存)
pm = dynamic
pm.max_children = 30
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
大服务器(8G以上)
pm = dynamic
pm.max_children = 80
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 40
七、其他优化参数
request_terminate_timeout
单个请求最长执行时间,超时就杀掉。
request_terminate_timeout = 30s
slow log
慢日志,看看哪个请求慢。
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 10s
php_admin_value[memory_limit]
每个PHP进程的内存限制。
php_admin_value[memory_limit] = 128M
八、改完配置重载
systemctl reload php-fpm
或者:
systemctl restart php-fpm
九、验证效果
看进程数
ps aux | grep php-fpm | wc -l
看内存
free -h
看负载
top
十、常见坑
坑1:max_children设太大
比如2G内存设了100个进程,内存直接爆。
解决: 按上面的公式算,别拍脑袋。
坑2:改完配置不生效
忘了重载。
解决:
systemctl reload php-fpm
坑3:进程数一直涨
有慢请求,占着进程不放。
检查:
request_terminate_timeout = 30s
设个超时,超时就杀。
坑4:502 Bad Gateway
进程都忙不过来,Nginx连不上FPM。
解决: 加max_children,或者优化慢请求。
坑5:用了static模式
static固定进程数,不用就浪费内存。
推荐: 用dynamic或ondemand。
十一、排查步骤
第一步:看是不是FPM进程多
ps aux | grep php-fpm | wc -l
第二步:看内存够不够
free -h
第三步:看有没有慢请求
tail -f /var/log/php-fpm/slow.log
第四步:调整配置
改www.conf里的pm.max_children等参数。
第五步:重载验证
systemctl reload php-fpm
总结
记住:
- 进程数别设太大,按内存算
- 公式:可用内存 / 每个进程平均内存
- 推荐用dynamic模式
- 设个request_terminate_timeout,防慢请求占着进程
- 改完记得reload
推荐配置:
pm = dynamic
pm.max_children = 30
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
request_terminate_timeout = 30s
遇到问题加QQ23979811 协助处理
Docker容器自动重启,restart=always参数
前言
服务器重启了,Docker容器没跟着起来?或者容器崩了,不自动重启?本文讲怎么配置自动重启。
一、restart参数
Docker用 --restart 参数控制容器的重启策略。
四种策略
| 策略 | 说明 |
|---|---|
no |
不自动重启(默认) |
on-failure |
非正常退出时重启 |
always |
总是自动重启 |
unless-stopped |
除非手动停了,否则一直重启 |
二、always策略
用法
docker run -d --name nginx --restart=always nginx
什么时候会重启
- 容器崩了(非正常退出)
- Docker服务重启
- 服务器重启(只要Docker开机自启)
特点
- 不管什么原因停了,都会自动起来
- 服务器重启后也会自动启动
三、unless-stopped策略
用法
docker run -d --name nginx --restart=unless-stopped nginx
和always的区别
- always:就算你手动停了,重启Docker后还是会起来
- unless-stopped:如果你手动停了,重启Docker后就不起来了
推荐用unless-stopped,更灵活。
四、on-failure策略
用法
docker run -d --name nginx --restart=on-failure:5 nginx
说明
- 只有非正常退出时才重启
:5表示最多重启5次,超过就不重启了
什么时候用
比如批处理任务,失败了重试几次,一直失败就算了。
五、no策略(默认)
docker run -d --name nginx --restart=no nginx
不自动重启,停了就停了。
六、修改已有容器的重启策略
运行中的容器
docker update --restart=always 容器名
不用删容器,直接改。
例子
docker update --restart=always nginx
docker update --restart=unless-stopped mysql
七、Docker Compose里的配置
services:
nginx:
image: nginx
restart: always
或者:
restart: unless-stopped
八、服务器开机自启
1. Docker服务开机自启
systemctl enable docker
2. 容器开机自启
只要容器设了 --restart=always 或 unless-stopped,Docker启动后容器就会自动启动。
验证
重启服务器试试:
reboot
重启完看看容器起来没:
docker ps
九、查看重启策略
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' 容器名
输出:
always
十、常见坑
坑1:设了always,服务器重启后没起来
原因: Docker服务没设开机自启。
解决:
systemctl enable docker
坑2:手动停了,又自动起来了
用了 always 策略,手动停了也会起来。
解决: 想彻底停掉:
docker update --restart=no 容器名
docker stop 容器名
坑3:一直重启,死循环
容器启动就崩,崩了又重启,死循环。
检查:
docker logs 容器名
看看为什么启动失败,先把问题修了。
坑4:on-failure重启次数
--restart=on-failure:5
最多重启5次,超过就不重启了。
注意: 这个5是次数,不是间隔。
十一、推荐配置
生产环境推荐
docker run -d \
--name nginx \
--restart=unless-stopped \
-p 80:80 \
nginx
- 服务器重启自动起来
- 手动停了就不自动起
- 灵活
数据库推荐
docker run -d \
--name mysql \
--restart=unless-stopped \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
总结
记住:
--restart=always总是自动重启--restart=unless-stopped推荐,手动停了不自动起- 改已有容器:
docker update --restart=xxx 容器名 - 服务器开机自启要先
systemctl enable docker
最常用:
docker run -d --name nginx --restart=unless-stopped nginx
遇到问题加QQ23979811 协助处理
Docker网络模式详解,bridge、host、none
前言
Docker容器怎么联网的?bridge、host、none这些网络模式啥区别?本文一次讲清楚。
一、Docker网络模式
Docker有5种网络模式:
- bridge:默认模式,桥接网络
- host:主机网络,和宿主机共用
- none:无网络
- container:和另一个容器共用网络
- 自定义网络:自己建的网络
二、bridge模式(默认)
是什么
Docker默认的网络模式。每个容器有自己的虚拟网络,通过docker0网桥和宿主机通信。
特点
- 每个容器有自己的IP
- 容器之间可以通过容器名互相访问
- 外部要访问容器,要靠
-p端口映射
用法
docker run -d --name nginx -p 80:80 nginx
没指定 --network,默认就是bridge。
容器之间通信
docker run -d --name mysql mysql:5.7
docker run -d --name web --link mysql nginx
或者用自定义网络,容器名直接解析:
docker network create mynet
docker run -d --name mysql --network mynet mysql:5.7
docker run -d --name web --network mynet nginx
web容器里直接用 mysql 这个主机名就能连数据库。
三、host模式
是什么
容器直接用宿主机的网络,没有自己的虚拟网卡。
特点
- 没有独立IP,和宿主机共用
- 不用
-p映射,直接用宿主机的端口 - 性能最好,因为少了一层网络转发
- 安全性差点,容器直接暴露在宿主机网络上
用法
docker run -d --name nginx --network host nginx
注意
host模式下,-p 参数无效。容器用什么端口,直接就是宿主机的端口。
比如Nginx监听80,宿主机的80就被占了。
四、none模式
是什么
容器没有网络,完全断网。
特点
- 没有网卡,没有IP
- 只能通过localhost访问
- 适合不需要联网的任务,比如批量处理文件
用法
docker run -d --name test --network none nginx
查看
docker exec test ip addr
只能看到lo回环网卡。
五、container模式
是什么
新创建的容器和一个已有的容器共用网络。
特点
- 两个容器共用同一个网络命名空间
- 用
127.0.0.1就能互相访问 - 适合一个应用拆成多个容器的场景
用法
# 先跑一个web容器
docker run -d --name web nginx
# 再跑一个sidecar容器,和web共用网络
docker run -d --name sidecar --network container:web busybox
sidecar容器里 127.0.0.1 就是web容器的localhost。
六、自定义网络
创建网络
docker network create mynet
使用网络
docker run -d --name mysql --network mynet mysql:5.7
docker run -d --name redis --network mynet redis
好处
- 容器名自动解析,不用写IP
- 网络隔离,不同网络的容器不能互相访问
- 更灵活
查看网络
docker network ls
查看网络详情
docker network inspect mynet
七、常用命令
查看容器网络模式
docker inspect -f '{{.HostConfig.NetworkMode}}' 容器名
查看容器IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名
查看所有网络
docker network ls
删除网络
docker network rm mynet
八、常见场景选什么模式
场景1:跑Web服务,要外网访问
选bridge,用 -p 映射端口。
场景2:追求高性能,比如数据库
选host,少一层转发,性能好。
场景3:不需要联网的任务
选none,安全。
场景4:两个容器紧耦合
选container,共用网络。
场景5:多容器编排
选自定义网络,容器名自动解析。
九、常见坑
坑1:容器之间ping不通
bridge模式下,容器之间默认是通的,但如果用了none就不通。
检查: 网络模式是什么?
docker inspect 容器名 | grep NetworkMode
坑2:host模式下端口冲突
host模式直接用宿主机端口,端口被占了就起不来。
检查: 宿主机端口有没有被占。
坑3:容器名解析不了
默认bridge网络不支持容器名解析。
解决: 用自定义网络。
坑4:改了网络模式,要重新建容器
网络模式是容器创建时定的,不能改。
解决: 删掉容器重新跑。
总结
记住:
- bridge:默认,端口映射,常用
- host:共用宿主机网络,性能好
- none:断网,安全
- container:和别的容器共用网络
- 自定义网络:容器名自动解析,推荐
最常用:
docker network create mynet
docker run -d --name nginx --network mynet nginx
遇到问题加QQ23979811 协助处理
Docker运行Nginx,挂载配置文件和网页
前言
用Docker跑Nginx,想改网站文件、改配置,每次进容器里改太麻烦。挂载出来就方便多了。本文讲怎么挂载网页和配置文件。
一、基本运行
最简单的跑法
docker run -d --name nginx -p 80:80 nginx
问题: 网站文件和配置都在容器里,改起来不方便。
二、挂载网页目录
完整命令
docker run -d \
--name nginx \
-p 80:80 \
-v /data/www:/usr/share/nginx/html \
nginx
解释
- 宿主机
/data/www目录 - 容器里
/usr/share/nginx/html目录
这样直接在宿主机改网页文件,刷新浏览器就生效了。
测试
在宿主机创建index.html:
echo "<h1>Hello Docker Nginx</h1>" > /data/www/index.html
浏览器访问:
http://服务器IP
就能看到了。
三、挂载配置文件
1. 先从容器里拷出默认配置
docker run -d --name nginx nginx
docker cp nginx:/etc/nginx/nginx.conf /data/nginx/nginx.conf
docker cp nginx:/etc/nginx/conf.d /data/nginx/conf.d
docker rm -f nginx
2. 挂载配置文件
docker run -d \
--name nginx \
-p 80:80 \
-v /data/www:/usr/share/nginx/html \
-v /data/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /data/nginx/conf.d:/etc/nginx/conf.d \
nginx
3. 改配置
直接在宿主机改 /data/nginx/conf.d/default.conf,改完重载:
docker exec nginx nginx -s reload
四、挂载日志
docker run -d \
--name nginx \
-p 80:80 \
-v /data/www:/usr/share/nginx/html \
-v /data/nginx/logs:/var/log/nginx \
nginx
日志直接在宿主机看:
tail -f /data/nginx/logs/access.log
五、Docker Compose完整配置
version: '3'
services:
nginx:
image: nginx:alpine
container_name: nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- /data/www:/usr/share/nginx/html
- /data/nginx/nginx.conf:/etc/nginx/nginx.conf
- /data/nginx/conf.d:/etc/nginx/conf.d
- /data/nginx/logs:/var/log/nginx
启动:
docker-compose up -d
六、常用操作
重载配置
改了配置文件后:
docker exec nginx nginx -s reload
查看日志
docker logs nginx
# 实时看
docker logs -f nginx
进容器
docker exec -it nginx sh
七、常见坑
坑1:挂载后网站403
原因: 宿主机目录权限不对。
解决:
chmod -R 755 /data/www
chown -R nginx:nginx /data/www
坑2:改了配置不生效
原因: 没重载配置。
解决:
docker exec nginx nginx -s reload
坑3:挂载文件不存在,变成目录
-v /data/nginx.conf:/etc/nginx/nginx.conf
如果 /data/nginx.conf 不存在,Docker会自动建一个叫nginx.conf的目录。
解决: 先创建文件:
touch /data/nginx.conf
坑4:端口被占用
80端口被宿主机的Nginx占了。
解决: 停掉宿主机的Nginx,或者换端口。
坑5:改了代码不生效
如果用了CDN或者浏览器缓存,强刷一下(Ctrl+F5)。
八、多站点配置
在 /data/nginx/conf.d/ 下建多个配置文件:
/data/nginx/conf.d/
├── site1.conf
├── site2.conf
└── default.conf
site1.conf:
server {
listen 80;
server_name site1.com;
root /data/www/site1;
index index.html;
}
改完重载:
docker exec nginx nginx -s reload
九、HTTPS配置
挂载证书:
docker run -d \
--name nginx \
-p 80:80 \
-p 443:443 \
-v /data/www:/usr/share/nginx/html \
-v /data/nginx/conf.d:/etc/nginx/conf.d \
-v /data/ssl:/etc/nginx/ssl \
nginx
配置文件里引用证书:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
root /data/www;
}
总结
记住:
- 挂载网页目录:
-v /data/www:/usr/share/nginx/html - 挂载配置文件:
-v /data/nginx/nginx.conf:/etc/nginx/nginx.conf - 挂载日志:
-v /data/nginx/logs:/var/log/nginx - 改完配置重载:
docker exec nginx nginx -s reload
最常用:
docker run -d --name nginx -p 80:80 \
-v /data/www:/usr/share/nginx/html \
-v /data/nginx/conf.d:/etc/nginx/conf.d \
nginx
遇到问题加QQ23979811 协助处理
Docker运行MySQL,数据持久化配置
前言
用Docker跑MySQL,删了容器数据就没了?那是没挂数据卷。本文讲怎么用Docker跑MySQL并持久化数据。
一、基本运行
最简单的跑法
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
问题: 删了容器,数据库里的数据全没了。
二、加数据卷持久化
完整命令
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
解释
-p 3306:3306端口映射-e MYSQL_ROOT_PASSWORD=123456设置root密码-v /data/mysql:/var/lib/mysql数据卷挂载- 宿主机
/data/mysql目录 - 容器里
/var/lib/mysql目录
- 宿主机
这样容器删了,数据还在宿主机上。
三、其他常用配置
1. 设置字符集
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
-v /data/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:5.7 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
2. 创建数据库和用户
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=mydb \
-e MYSQL_USER=myuser \
-e MYSQL_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
3. 挂载配置文件
先在宿主机创建my.cnf:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=1000
然后挂载:
docker run -d \
--name mysql \
-v /data/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
四、Docker Compose方式
version: '3'
services:
mysql:
image: mysql:5.7
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: mydb
volumes:
- /data/mysql:/var/lib/mysql
- /data/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
启动:
docker-compose up -d
五、连接MySQL
进入容器连接
docker exec -it mysql mysql -uroot -p123456
从宿主机连接
mysql -h127.0.0.1 -P3306 -uroot -p123456
用Navicat等工具
- 主机:服务器IP
- 端口:3306
- 用户名:root
- 密码:123456
六、备份和恢复
备份数据库
docker exec mysql mysqldump -uroot -p123456 mydb > /data/backup/mydb.sql
恢复数据库
docker exec -i mysql mysql -uroot -p123456 mydb < /data/backup/mydb.sql
七、常见坑
坑1:密码不对
报错:
Access denied for user 'root'@'localhost'
检查: 环境变量 MYSQL_ROOT_PASSWORD 设了没?
坑2:权限问题
宿主机 /data/mysql 目录权限不对:
chmod -R 777 /data/mysql
坑3:端口被占用
3306端口被宿主机的MySQL占了:
Bind for 0.0.0.0:3306 failed: port is already allocated
解决: 换个端口:
-p 3307:3306
坑4:数据没持久化
没加 -v 挂载,删了容器数据就没了。
检查: 有没有 -v /data/mysql:/var/lib/mysql?
坑5:第一次启动慢
MySQL第一次启动要初始化数据,要等个十几秒。
等不及就先别连,过一会再试。
坑6:字符集不对,中文乱码
加参数:
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
八、推荐配置
docker run -d \
--name mysql \
--restart=always \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=你的密码 \
-v /data/mysql:/var/lib/mysql \
-v /data/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:5.7
--restart=always开机自动启动- 数据挂载到
/data/mysql - 配置文件挂载
总结
记住:
- 一定要挂数据卷,不然删容器数据就没了
- 用
-e MYSQL_ROOT_PASSWORD设密码 - 用
-p 3306:3306映射端口 - 配置文件也可以挂载进去
最常用:
docker run -d --name mysql -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
遇到问题加QQ23979811 协助处理
Dockerfile编写教程,构建自己的镜像
前言
想用Docker跑自己的项目,不能每次都手动装环境吧?写个Dockerfile,一键构建镜像。本文讲怎么写Dockerfile。
一、什么是Dockerfile
Dockerfile就是一个文本文件,里面写了怎么构建镜像的步骤。
就像写脚本一样,告诉Docker:
- 基于哪个基础镜像
- 装什么软件
- 复制什么文件
- 启动什么命令
二、基本结构
# 基于哪个镜像
FROM nginx:alpine
# 维护者信息
MAINTAINER yourname <email@xx.com>
# 工作目录
WORKDIR /usr/share/nginx/html
# 复制文件
COPY index.html .
# 暴露端口
EXPOSE 80
# 启动命令
CMD ["nginx", "-g", "daemon off;"]
三、常用指令
FROM:基础镜像
FROM nginx:alpine
FROM php:7.4-fpm
FROM mysql:5.7
WORKDIR:工作目录
WORKDIR /app
后面的命令都在这个目录里执行。
COPY:复制文件
COPY index.html /usr/share/nginx/html/
COPY ./src /app
RUN:构建时执行命令
RUN apt-get update && apt-get install -y vim
构建镜像的时候执行。
CMD:容器启动时执行
CMD ["nginx", "-g", "daemon off;"]
容器启动后跑的命令。
EXPOSE:暴露端口
EXPOSE 80
EXPOSE 443
只是声明,实际用的时候还要用-p映射。
ENV:设置环境变量
ENV MYSQL_ROOT_PASSWORD=123456
ENV APP_ENV=production
VOLUME:数据卷
VOLUME ["/var/lib/mysql"]
四、实战例子
例子1:部署静态网站
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY index.html .
COPY about.html .
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
例子2:部署PHP项目
FROM php:7.4-fpm
WORKDIR /var/www/html
COPY . .
RUN docker-php-ext-install mysqli pdo pdo_mysql
EXPOSE 9000
CMD ["php-fpm"]
例子3:Python应用
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
五、构建镜像
构建命令
docker build -t mynginx:v1 .
-t给镜像起名字和标签.当前目录找Dockerfile
查看构建过程
docker build --progress=plain -t mynginx:v1 .
指定Dockerfile路径
docker build -f docker/Dockerfile -t mynginx:v1 .
六、常用优化技巧
1. 用小镜像
用alpine版本,小很多:
FROM nginx:alpine
2. 合并RUN命令
RUN apt-get update && \
apt-get install -y vim wget && \
rm -rf /var/lib/apt/lists/*
不要写多个RUN,合并成一个,减少层数。
3. .dockerignore文件
不想复制的文件写在.dockerignore里:
.git
node_modules
*.log
4. 多层缓存
把不变的放前面,变的放后面。
# 先复制requirements.txt,装依赖(这个不常变)
COPY requirements.txt .
RUN pip install -r requirements.txt
# 再复制代码(这个常变)
COPY . .
七、常见坑
坑1:Dockerfile文件名不对
必须叫 Dockerfile,首字母大写,没有后缀。
坑2:构建时找不到文件
docker build -t mynginx:v1 .
最后那个点不能少,是构建上下文。
坑3:COPY路径不对
COPY index.html .
这个路径是相对于构建上下文的,不是Dockerfile所在目录。
坑4:CMD和RUN搞混
RUN是构建镜像的时候跑CMD是容器启动的时候跑
坑5:镜像太大
用alpine版本,或者多阶段构建。
八、多阶段构建
# 构建阶段
FROM node:16 AS build
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
这样最终镜像很小,只有编译后的文件。
总结
记住:
FROM基础镜像WORKDIR工作目录COPY复制文件RUN构建时执行CMD启动时执行docker build -t 名字 .构建镜像
最常用:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
遇到问题加QQ23979811 协助处理
Docker查看容器资源占用,stats命令
前言
容器跑多了,哪个占CPU、哪个占内存,一眼看出来。本文讲Docker stats命令。
一、基本用法
查看所有运行中的容器
docker stats
输出:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a1b2c3d4e5f6 mysql 2.50% 500MiB / 2GiB 25.0% 1MB/2MB 10MB/5MB 30
f7e8d9c0b1a2 nginx 0.10% 20MiB / 2GiB 1.0% 5MB/3MB 1MB/0B 5
列解释
- CPU %:CPU使用率
- MEM USAGE / LIMIT:内存使用 / 内存限制
- MEM %:内存使用率
- NET I/O:网络收发流量
- BLOCK I/O:磁盘读写
- PIDS:进程数
二、查看单个容器
docker stats 容器名
只看某一个容器。
三、只看一次,不刷新
默认是实时刷新的,按Ctrl+C退出。
只看一次:
docker stats --no-stream
四、自定义格式
只看CPU和内存
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
JSON格式输出
docker stats --format json --no-stream
五、其他常用命令
查看容器占用磁盘
docker system df
查看单个容器磁盘占用
docker ps -s
看SIZE列,就是容器写的磁盘大小。
查看容器网络IO
docker stats --no-stream
看NET I/O列。
六、常见场景
场景1:哪个容器占CPU高?
docker stats
看CPU %列,高的那个就是。
场景2:哪个容器占内存高?
看MEM USAGE列。
场景3:某个容器网络流量大
看NET I/O列。
七、限制容器资源
跑的时候可以限制CPU和内存:
限制内存512M
docker run -d --memory 512m nginx
限制CPU 0.5核
docker run -d --cpus 0.5 nginx
同时限制
docker run -d \
--memory 512m \
--cpus 0.5 \
nginx
八、常见坑
坑1:stats一直刷新,退不出来
按Ctrl+C退出。
坑2:看不准CPU使用率
Docker stats显示的是CPU使用率百分比,多核的话可能超过100%(比如4核跑满就是400%)。
坑3:内存看的是驻留内存
MEM USAGE是容器实际用的内存,包括缓存。
坑4:容器挂了,stats看不到了
docker stats
只看运行中的容器,停止的看不到。
总结
记住:
docker stats看所有运行中的容器资源占用- 看CPU、内存、网络、磁盘IO
--no-stream只看一次- 跑容器时可以限制资源
最常用:
docker stats
遇到问题加QQ23979811 协助处理
Docker删除所有停止的容器,一键清理
前言
用Docker久了,一堆停止的容器占磁盘,一个个删太麻烦。本文讲怎么一键清理。
一、查看所有停止的容器
先看看有多少个停止的容器:
docker ps -a
看STATUS列,显示Exited的就是停止的。
只看停止的:
docker ps -a -f status=exited
二、删除所有停止的容器
一键清理
docker container prune
输出:
Total reclaimed space: 1.2GB
直接删掉所有停止的容器。
确认提示
默认会问你:
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N]
输入y确认。
跳过确认
docker container prune -f
加个 -f 直接删,不问。
三、其他清理命令
删除所有没用的镜像
docker image prune
只删悬空镜像(dangling images),就是没有标签的。
删所有没用的镜像(包括没在用的)
docker image prune -a
清理所有没用的东西
docker system prune
包括:
- 停止的容器
- 没用的网络
- 悬空镜像
- 构建缓存
清理所有没用的东西(包括镜像)
docker system prune -a
连没在用的镜像也删了。
清理数据卷
docker volume prune
注意: 这个会删没用的数据卷,里面的数据也没了!
四、手动删除单个容器
如果只想删某一个:
docker rm 容器ID或名字
强制删除运行中的容器:
docker rm -f 容器ID或名字
五、批量删除停止的容器
方法1:用docker rm
docker rm $(docker ps -a -q -f status=exited)
解释:
docker ps -a -q列出所有容器ID-f status=exited只筛停止的docker rm删掉
方法2:用docker container prune
docker container prune -f
推荐用这个,简单。
六、查看磁盘占用
清理之前看看占了多少:
docker system df
输出:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 20 5 10GB 7GB (70%)
Containers 15 5 500MB 400MB (80%)
Local Volumes 8 3 2GB 1GB (50%)
Build Cache - - 1GB 800MB
看RECLAIMABLE列,就是可以回收的。
七、常见场景
场景1:测试完一堆容器,想全清了
docker container prune -f
场景2:磁盘满了,全面清理
docker system prune -a -f --volumes
-a删所有没用的镜像-f不问--volumes连数据卷也删
注意: 这个很猛,数据卷也删了,重要数据先备份!
场景3:只清理镜像,不动容器
docker image prune -a -f
八、常见坑
坑1:删了数据卷,数据没了
docker system prune --volumes
加了 --volumes 会删没用的数据卷。
注意: 数据库的数据卷别删!
坑2:删了镜像,重新拉要很久
docker image prune -a
把所有没在用的镜像都删了,下次用还要重新拉。
建议: 常用镜像留着,别全删。
坑3:误删了运行中的容器?
docker container prune 只删停止的,运行中的删不了。
放心,安全。
坑4:删了容器,数据卷还在
docker rm 容器名
只删容器,数据卷还在。
想连数据卷一起删:
docker rm -v 容器名
九、定期清理脚本
写个脚本,定期清理:
#!/bin/bash
# 清理停止的容器
docker container prune -f
# 清理悬空镜像
docker image prune -f
# 清理没用的网络
docker network prune -f
加到crontab,每周跑一次:
0 3 * * 0 /home/clean-docker.sh
总结
记住:
docker container prune删所有停止的容器docker image prune -a删所有没用的镜像docker system prune全面清理- 删数据卷要小心,别把数据库删了
最常用:
docker container prune -f
遇到问题加QQ23979811 协助处理
Docker数据卷挂载,容器数据持久化
前言
删了Docker容器,数据全没了?那是因为你没挂数据卷。本文讲怎么用数据卷让容器数据持久化。
一、为什么需要数据卷
容器里的数据,容器删了就没了。
docker run -d --name mysql mysql:5.7
# 删了容器,数据就没了
docker rm -f mysql
解决: 把数据存到宿主机,容器删了数据还在。
二、三种数据持久化方式
1. 绑定挂载(bind mount)
把宿主机的目录直接挂到容器里。
docker run -v /宿主机路径:/容器路径 镜像名
例子:
docker run -d \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
特点: 简单直接,数据在你自己的目录里。
2. 命名卷(named volume)
Docker管理的数据卷。
docker volume create mydata
docker run -v mydata:/var/lib/mysql mysql:5.7
特点: Docker帮你管理位置,不用你关心存在哪。
3. 临时挂载(tmpfs)
存在内存里,重启就没。
docker run --tmpfs /tmp 镜像名
特点: 临时用,存敏感数据。
三、常用场景
场景1:MySQL数据持久化
docker run -d \
--name mysql \
-v /data/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
场景2:Nginx挂载网站文件
docker run -d \
--name nginx \
-v /data/www:/usr/share/nginx/html \
-p 80:80 \
nginx
场景3:挂载配置文件
docker run -d \
-v /data/nginx/nginx.conf:/etc/nginx/nginx.conf \
nginx
场景4:挂载日志
docker run -d \
-v /data/logs/nginx:/var/log/nginx \
nginx
四、Docker Compose里的挂载
services:
mysql:
image: mysql:5.7
volumes:
- /data/mysql:/var/lib/mysql
# 或者用命名卷
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
五、常用命令
查看所有数据卷
docker volume ls
查看数据卷详情
docker volume inspect 数据卷名
删除没用的数据卷
docker volume prune
查看容器挂载
docker inspect -f '{{.Mounts}}' 容器名
六、只读挂载
只想让容器读,不让写:
docker run -v /data/www:/usr/share/nginx/html:ro nginx
后面加个 :ro 就是只读。
七、常见坑
坑1:改了配置文件不生效
挂了配置文件,改了宿主机的文件,重启容器还是旧的。
原因: 容器没真正重启。
解决:
docker restart 容器名
坑2:权限问题
挂载的目录,容器里的用户读不了。
原因: 宿主机目录权限不对。
解决:
chmod -R 777 /data/mysql
坑3:Windows/Mac路径问题
Windows路径写法不一样:
docker run -v D:\data:/var/lib/mysql mysql
Mac/Linux用:
docker run -v /Users/xxx/data:/var/lib/mysql mysql
坑4:挂载文件不存在
宿主机的文件不存在,Docker会自动建一个目录。
比如:
docker run -v /data/nginx.conf:/etc/nginx/nginx.conf nginx
如果 /data/nginx.conf 不存在,Docker会建一个叫 nginx.conf 的目录,容器里就挂错了。
解决: 先创建文件:
touch /data/nginx.conf
坑5:数据卷删了数据就没了
docker volume rm mydata
数据卷删了,里面的数据也没了。
解决: 重要数据定期备份。
八、最佳实践
- 数据库一定要挂载数据卷,不然容器删了数据就没了
- 配置文件挂载到宿主机,改起来方便
- 日志挂载到宿主机,方便查看和切割
- 网站文件挂载到宿主机,更新代码不用重新打镜像
总结
记住:
-v 宿主机路径:容器路径就是挂载- 数据库一定要挂数据卷
- 删容器不删数据,因为数据在宿主机
- 挂载文件不存在会变成目录,要注意
最常用:
docker run -v /data/mysql:/var/lib/mysql mysql
遇到问题加QQ23979811 协助处理
Docker端口映射,-p参数用法详解
前言
容器跑起来了,但外部访问不了,就是端口没映射好。本文讲Docker端口映射的各种用法。
一、什么是端口映射
Docker容器有自己的内部网络,外部要访问容器里的服务,得把宿主机的端口映射到容器的端口。
二、基本用法
格式
-p 宿主机端口:容器端口
例子
docker run -d -p 8080:80 nginx
意思:访问宿主机的8080端口,转发到容器的80端口。
浏览器访问
http://服务器IP:8080
三、各种写法
1. 指定宿主机端口和容器端口
-p 8080:80
2. 只指定容器端口,宿主机随机分配
docker run -d -P nginx
大写P,宿主机随机找个空闲端口。
3. 绑定指定IP
-p 127.0.0.1:8080:80
只允许本机访问,外网访问不了。
4. UDP端口
-p 53:53/udp
5. 映射多个端口
docker run -d \
-p 80:80 \
-p 443:443 \
-p 2222:22 \
nginx
四、查看端口映射
查看容器端口
docker port 容器名
输出:
80/tcp -> 0.0.0.0:8080
查看详细信息
docker ps
看PORTS列。
五、Docker Compose里的端口映射
services:
nginx:
image: nginx
ports:
- "80:80"
- "443:443"
- "127.0.0.1:8080:80"
六、常见场景
场景1:跑Nginx
docker run -d -p 80:80 --name mynginx nginx
场景2:跑MySQL
docker run -d -p 3306:3306 --name mysql \
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
场景3:跑Redis
docker run -d -p 6379:6379 --name redis redis
场景4:多个容器跑同一个端口
比如跑两个Nginx,分别用不同端口:
docker run -d -p 8081:80 --name nginx1 nginx
docker run -d -p 8082:80 --name nginx2 nginx
七、端口被占用怎么办
报错
Bind for 0.0.0.0:80 failed: port is already allocated
查谁占用了80端口
netstat -tlnp | grep :80
# 或者
lsof -i:80
解决
- 换个端口:
-p 8080:80 - 或者把占用端口的程序关掉
八、端口映射的坑
坑1:只映射了容器端口,没映射宿主机端口
docker run -d -p 80 nginx
这样宿主机随机分配端口,不好记。
坑2:防火墙没开
端口映射了,但防火墙挡了,外网还是访问不了。
解决: 开放端口:
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
坑3:改不了端口映射
容器启动后,想改端口映射,改不了。
解决: 删掉容器重新跑。容器数据用卷挂载了就不怕丢。
坑4:绑定127.0.0.1后外网访问不了
-p 127.0.0.1:8080:80
这个只能本机访问,外网访问不了。
原因: 故意绑的本机。
解决: 改成 0.0.0.0:8080:80 或者直接 8080:80。
总结
记住:
- 基本格式:
-p 宿主机端口:容器端口 - 多个端口就写多个
-p - 端口被占用就换一个
- 防火墙也要开
常用:
docker run -d -p 80:80 --name nginx nginx
遇到问题加QQ23979811 协助处理
Docker进入容器内部,exec和attach区别
前言
要进容器里改配置、看日志,用什么命令?docker exec和docker attach有什么区别?本文讲清楚。
一、docker exec(推荐)
作用
在运行中的容器里开一个新进程。
进入容器
docker exec -it 容器名 /bin/bash
或者:
docker exec -it 容器名 sh
参数说明
| 参数 | 说明 |
|---|---|
| -i | 保持交互 |
| -t | 分配终端 |
| -it | 合起来用 |
退出
输入 exit 或者按 Ctrl+D。
关键: 退出后容器还在运行,不受影响。
执行单个命令
不进交互模式,直接执行命令:
docker exec 容器名 ls /var/www/html
docker exec 容器名 cat /etc/nginx/nginx.conf
docker exec 容器名 php -v
二、docker attach
作用
连接到容器正在运行的主进程。
用法
docker attach 容器名
危险!
退出会导致容器停止!
按 Ctrl+C 退出后,容器就停了。
怎么安全退出
按 Ctrl+P 然后 Ctrl+Q,这样退出不会停容器。
三、exec和attach区别
| 对比 | exec | attach |
|---|---|---|
| 原理 | 开新进程 | 连接主进程 |
| 退出后容器 | 继续运行 | 会停止 |
| 常用场景 | 进容器操作 | 看主进程输出 |
| 推荐度 | 推荐 | 不推荐 |
记住: 日常用exec,别用attach。
四、常见场景
场景1:进容器改配置
docker exec -it mynginx /bin/bash
场景2:在容器里执行PHP命令
docker exec myphp php artisan migrate
场景3:看容器里的日志文件
docker exec mynginx tail -f /var/log/nginx/access.log
场景4:容器里没bash
有些精简镜像没有bash,用sh:
docker exec -it 容器名 sh
场景5:以root用户进入
docker exec -u root -it 容器名 /bin/bash
五、如果容器没bash怎么办
用nsenter
# 先拿容器PID
PID=$(docker inspect --format "{{.State.Pid}}" 容器名)
# 进入
nsenter --target $PID --mount --uts --ipc --net --pid
或者用docker run
用同一个镜像开个交互式容器:
docker run -it --rm 镜像名 /bin/bash
六、常用命令汇总
| 命令 | 说明 |
|---|---|
| docker exec -it 容器名 /bin/bash | 进容器 |
| docker exec 容器名 命令 | 执行命令 |
| docker exec -u root -it 容器名 /bin/bash | 以root进 |
| docker attach 容器名 | 连接主进程(慎用) |
常见坑
坑1:attach退出后容器停了
用attach进去,按Ctrl+C退出,容器就停了。
解决: 用exec,或者Ctrl+P Ctrl+Q退出。
坑2:进容器报/ bin/bash not found
镜像里没有bash。
解决: 用sh:
docker exec -it 容器名 sh
坑3:进容器报permission denied
不是root用户,权限不够。
解决: 加 -u root:
docker exec -u root -it 容器名 /bin/bash
坑4:exec进不去,说容器没运行
容器停了,exec进不去。
解决: 先启动容器:
docker start 容器名
docker exec -it 容器名 /bin/bash
坑5:多个终端连同一个容器
exec可以开多个终端,互不影响。
这是exec比attach好的地方,attach只能连一个。
总结
记住两点:
- 日常用
docker exec -it 容器名 /bin/bash - 别用attach,退出会把容器搞停
补充: 精简镜像没有bash,用sh代替。
遇到问题加QQ23979811 协助处理
Docker查看容器IP,docker inspect命令
前言
容器之间要互相通信,得知道容器的IP。本文讲怎么用docker inspect查看容器IP和详细信息。
一、查看容器IP
最简单的方法
docker inspect 容器名
输出一大串JSON,找IPAddress字段。
只看IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名
直接输出IP地址,比如:172.17.0.2
查看所有运行中容器的IP
docker ps -q | xargs docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
输出:
/mynginx - 172.17.0.2
/mymysql - 172.17.0.3
/myphp - 172.17.0.4
二、docker inspect常用用法
查看容器挂载
docker inspect -f '{{.Mounts}}' 容器名
查看容器启动命令
docker inspect -f '{{.Config.Cmd}}' 容器名
查看容器环境变量
docker inspect -f '{{.Config.Env}}' 容器名
查看容器端口映射
docker inspect -f '{{.NetworkSettings.Ports}}' 容器名
查看容器网络
docker inspect -f '{{.NetworkSettings.Networks}}' 容器名
查看容器状态
docker inspect -f '{{.State.Status}}' 容器名
查看容器启动时间
docker inspect -f '{{.State.StartedAt}}' 容器名
查看容器日志路径
docker inspect -f '{{.LogPath}}' 容器名
三、查看镜像信息
查看镜像详细信息
docker inspect 镜像名
查看镜像作者
docker inspect -f '{{.Author}}' nginx
查看镜像默认启动命令
docker inspect -f '{{.Config.Cmd}}' nginx
四、容器之间怎么通信
用容器名通信(推荐)
Docker默认网络里,容器可以用容器名互相访问:
# 在nginx容器里ping mysql
docker exec mynginx ping mysql
不用记IP,直接用容器名就行。
用自定义网络
# 创建网络
docker network create mynet
# 容器加入网络
docker run --name mysql --network mynet -d mysql:5.7
docker run --name nginx --network mynet -d nginx
五、常见场景
场景1:Nginx反向代理连PHP
nginx配置里:
fastcgi_pass php:9000;
这里的php就是容器名,Docker会自动解析成容器IP。
场景2:PHP连MySQL
<?php
$pdo = new PDO('mysql:host=mysql;dbname=mydb', 'root', '123456');
?>
host填mysql,就是MySQL容器的名字。
六、容器IP会变吗?
会的。
容器重启后,IP可能会变。所以不要硬编码IP,用容器名通信最稳。
如果要固定IP: 用自定义网络,指定静态IP。
# docker-compose.yml
services:
mysql:
networks:
mynet:
ipv4_address: 172.20.0.10
常见坑
坑1:inspect输出太多,找不到IP
解决: 用 -f 参数过滤,只看你要的字段。
坑2:容器停了就看不到IP
容器停止状态下,IPAddress是空的。
解决: 先启动容器:docker start 容器名
坑3:不同网络的容器互相ping不通
原因: 容器在不同网络里。
解决: 把它们加到同一个网络:
docker network connect mynet 容器名
坑4:用容器名ping不通
原因: 不是默认网络,或者Docker版本太老。
解决: 用自定义网络,或者直接用IP。
坑5:host网络模式看不到IP
用 --network=host 启动的容器,IP和宿主机一样。
解决: 不用查了,就是宿主机的IP。
总结
常用命令:
| 命令 | 说明 |
|---|---|
| docker inspect 容器名 | 看容器全部信息 |
| docker inspect -f '{{.NetworkSettings.IPAddress}}' 容器名 | 只看IP |
| docker inspect -f '{{.Mounts}}' 容器名 | 看挂载 |
| docker inspect -f '{{.Config.Env}}' 容器名 | 看环境变量 |
记住: 容器之间用容器名通信,别硬编码IP,重启就变了。
遇到问题加QQ23979811 协助处理
Docker容器内时间和宿主机不一致修复
前言
Docker容器里的时间和宿主机差了8个小时,日志时间不对,定时任务也跑偏。本文讲怎么修复容器时区问题。
一、问题现象
# 宿主机时间
date
# 输出:Thu Oct 8 08:14:01 CST 2026
# 容器里时间
docker exec 容器名 date
# 输出:Thu Oct 8 00:14:01 UTC 2026
差了8个小时,因为容器默认用UTC时区。
二、查看容器时区
docker exec 容器名 date
或者:
docker exec 容器名 cat /etc/timezone
三、修复方法
方法1:挂载时区文件(推荐)
启动容器时挂载宿主机的时区文件:
docker run -v /etc/localtime:/etc/localtime:ro 镜像名
这样容器就和宿主机用同一个时区了。
方法2:设置环境变量
docker run -e TZ=Asia/Shanghai 镜像名
方法3:进容器手动改
# 进容器
docker exec -it 容器名 bash
# 装时区数据
apt-get update && apt-get install -y tzdata
# 设置时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo "Asia/Shanghai" > /etc/timezone
# 验证
date
方法4:Docker Compose设置
在docker-compose.yml里加:
services:
app:
image: xxx
environment:
- TZ=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
四、PHP容器额外设置
PHP的时区和系统时区是两回事,还要改php.ini:
[Date]
date.timezone = Asia/Shanghai
或者在代码里设:
<?php
date_default_timezone_set('Asia/Shanghai');
?>
五、MySQL容器额外设置
MySQL的时区也要改:
-- 查看当前时区
SELECT @@global.time_zone;
-- 设置为东八区
SET GLOBAL time_zone = '+8:00';
永久生效改my.cnf:
[mysqld]
default-time-zone = '+8:00'
六、验证
# 宿主机时间
date
# 容器时间
docker exec 容器名 date
两个时间一致就对了。
常见坑
坑1:改了时区不生效
改了时区文件,重启容器又变回UTC了。
原因: 容器重启后文件系统重置了。
解决: 用挂载的方式,不要进容器改。
坑2:只改了系统时区,PHP时区不对
系统时间对了,但PHP date()还是错的。
原因: PHP有自己的时区设置。
解决: 改php.ini的date.timezone。
坑3:日志时间不对
日志里的时间还是UTC。
原因: 程序启动时读的时区,改了时区要重启程序。
解决: 重启容器或重启程序。
坑4:Windows/Mac Docker Desktop
Windows和Mac上Docker Desktop的时区处理不一样。
解决: 直接用TZ环境变量最稳。
坑5:时区列表找不到Asia/Shanghai
原因: 容器里没装tzdata。
解决: 先装tzdata:
apt-get install -y tzdata
总结
最稳的方法:
- 挂载
/etc/localtime:/etc/localtime:ro - 加环境变量
TZ=Asia/Shanghai - PHP改
date.timezone - MySQL改
default-time-zone
记住: 时区不一致是Docker最常见的问题之一,部署完第一件事先验证时间。
遇到问题加QQ23979811 协助处理
Docker Compose部署LNMP环境完整示例
前言
手动装Nginx、PHP、MySQL太麻烦,用Docker Compose一键部署LNMP环境,几分钟搞定。
一、项目结构
lnmp/
├── docker-compose.yml
├── nginx/
│ ├── conf.d/
│ │ └── default.conf
│ └── nginx.conf
├── php/
│ └── php.ini
├── mysql/
│ └── my.cnf
└── www/
└── index.php
二、docker-compose.yml
version: '3'
services:
nginx:
image: nginx:latest
container_name: lnmp_nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./www:/var/www/html
depends_on:
- php
networks:
- lnmp
php:
image: php:fpm
container_name: lnmp_php
volumes:
- ./www:/var/www/html
- ./php/php.ini:/usr/local/etc/php/php.ini
networks:
- lnmp
mysql:
image: mysql:5.7
container_name: lnmp_mysql
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: mydb
networks:
- lnmp
networks:
lnmp:
driver: bridge
三、Nginx配置
nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;
}
}
四、PHP配置
php/php.ini
[PHP]
date.timezone = Asia/Shanghai
upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 128M
五、MySQL配置
mysql/my.cnf
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
六、测试文件
www/index.php
<?php
phpinfo();
?>
七、启动
cd lnmp
docker-compose up -d
查看状态
docker-compose ps
访问
http://localhost
能看到phpinfo页面就是成功了。
八、常用命令
| 命令 | 说明 |
|---|---|
| docker-compose up -d | 启动 |
| docker-compose down | 停止并删除容器 |
| docker-compose restart | 重启 |
| docker-compose logs -f | 看日志 |
| docker-compose exec php bash | 进PHP容器 |
| docker-compose exec mysql bash | 进MySQL容器 |
九、连接MySQL
从宿主机连接
mysql -h 127.0.0.1 -P 3306 -u root -p123456
从PHP连接
<?php
$pdo = new PDO('mysql:host=mysql;dbname=mydb', 'root', '123456');
echo "连接成功";
?>
注意:host填mysql,不是localhost,是docker-compose.yml里的服务名。
十、安装PHP扩展
进入PHP容器
docker-compose exec php bash
安装pdo_mysql
docker-php-ext-install pdo_mysql
docker-php-ext-install mysqli
重启PHP
docker-compose restart php
常见坑
坑1:Nginx报502
502 Bad Gateway,原因是PHP容器没启动,或者地址不对。
解决:确认PHP容器在运行,fastcgi_pass填服务名php:9000。
坑2:MySQL启动失败
原因:数据目录权限不对,或者密码没设。
解决:确认MYSQL_ROOT_PASSWORD设了,数据目录权限改成777。
坑3:文件修改不生效
改了www里的文件,浏览器刷新没变。
解决:确认volumes挂载了./www:/var/www/html。
坑4:端口被占用
port is already allocated,原因是宿主机80端口被占了。
解决:改端口,比如改成8080。
坑5:数据丢失
删了容器,MySQL数据没了。
解决:一定要挂载数据卷,./mysql/data:/var/lib/mysql。
总结
部署五步:建项目目录结构,写docker-compose.yml,写配置文件,docker-compose up -d启动,浏览器访问测试。
记住:数据一定要挂载,不然删容器数据就没了。
遇到问题加QQ23979811 协助处理