“运维,不只是修机器,它是一门关于系统、稳定与责任的艺术。”

一、写在前面

时间如梭,从最初接触 Linux 的那一行 ls -l 命令,到如今参与多个企业级系统架构的运维设计与保障,转眼已在运维行业耕耘十余年。今天借这个机会,回顾一下我的成长之路,也希望对一些正在走在这条路上的年轻人有所帮助。


二、我的职业路径

1. 初入职场:从基础命令开始

我最早的工作,是在一家公司负责 IDC 服务器的日常运维。那时候没有云,没有容器,所有事情都要亲自远程登录主机,执行脚本、部署服务、查看日志。

最常做的事:

  • ssh 登录数百台机器
  • 写 shell 脚本批量部署应用
  • 搭建 LAMP(Linux + Apache + MySQL + PHP)环境
  • 每天与网络问题、权限问题和磁盘告警打交道

这些工作虽然琐碎,但为我打下了坚实的基础。

2. 技术上升期:自动化与标准化

后来,我接触到了 Ansible、SaltStack、Zabbix、Prometheus 等运维工具,开始追求“自动化”、“可复用”、“高可用”这些关键词。

我做过的几件有成就感的事:

  • 用 Ansible 替换人工操作,提高部署效率 5 倍以上
  • 构建企业级 Prometheus + Grafana 监控系统
  • 优化线上发布流程,保障零宕机率滚动发布
  • 在多个项目中推行了运维文档标准与知识库建设

这时候,我也慢慢从“会用命令”变成了“用系统解决问题”的人。


三、我理解的“高级运维工程师”

很多人问我,高级运维到底要具备什么能力?我的答案是四个字:

稳定为王

一个高级运维,往往不是“会很多命令”,而是:

  • 能够在系统异常时迅速定位问题
  • 有能力设计弹性、高可用、高性能的架构
  • 理解开发、测试、网络、安全之间的协作关系
  • 具备“系统思维”,而不仅仅是“修复能力”

技术要强,视野要广,责任要扛,这是我对“高级”的理解。


四、我的技术理念

  1. 自动化优于手工,标准化优于个性
  2. 系统的稳定性是第一优先级
  3. 永远要留下“Plan B”(回滚机制、容灾方案)
  4. 日志、监控、告警三位一体,是守护系统的三大支柱
  5. 运维不该只是“灭火队”,更要是“设计师”

五、未来的方向

随着云原生、大模型、平台工程等技术的到来,运维正在快速演化。我也在持续学习以下方向:

  • Kubernetes 与平台自动化
  • DevOps 工程与 GitOps 流程
  • SRE 理念下的可观测性设计
  • 基础设施即代码(Terraform、Pulumi)
  • 安全运维(DevSecOps)与合规治理

这条路依然漫长,但我仍充满热情。


六、结语

这十年,运维从“幕后英雄”逐渐走向“技术中台”的核心力量。作为一名深耕一线的运维人,我很自豪,也很敬畏这份职业。

如果你也是一名运维工程师,希望这篇文章能让你有所共鸣;如果你是刚入行的新手,愿你在这条路上越走越远,不迷失方向,不丢失初心。

愿我们都能成为系统背后的那道光。

作为一名运维开发工程师,你经常会同时使用 Python 和 Bash 脚本进行自动化任务和系统管理。 这两门语言在语法和代码风格上存在显著差异,其中之一就是对代码块的定义方式。本文将深入探讨 Python 的强制缩进以及它与 Bash 脚本的对比,帮助你更好地理解如何在日常工作中有效运用这两种语言。

Python 的强制缩进

Python 采用独特的强制缩进机制来定义代码块,这与大多数其他编程语言(如 C、Java、JavaScript 等使用大括号 {})截然不同。 在 Python 中,相同的缩进级别表示属于同一个代码块。 不正确的缩进会导致 IndentationError,程序无法运行。

优点:

  • 增强可读性: 清晰的缩进使代码结构一目了然,提高了代码的可读性和可维护性。
  • 减少歧义: 强制缩进消除了代码块界限模糊的问题,降低了代码错误的可能性。

缺点:

  • 学习曲线: 对于习惯使用大括号定义代码块的程序员来说,需要适应 Python 的缩进规则。
  • 编辑器依赖: 选择合适的代码编辑器或 IDE 来保证一致的缩进至关重要。

示例:

1
2
3
4
5
def my_function(x):
if x > 10:
print("x is greater than 10")
else:
print("x is not greater than 10")

Bash 脚本中的代码块

Bash 脚本使用关键字(如 if, then, else, fi, for, do, done, while, until, case, esac 等)来定义代码块,并不依赖缩进。 虽然良好的缩进可以提高代码的可读性,但这并非 Bash 的语法要求。

优点:

  • 灵活的格式: 代码块的定义方式更加灵活,对缩进没有严格要求。
  • 与其他 shell 兼容性好: Bash 脚本的语法在大多数 Unix-like 系统中保持一致。

缺点:

  • 可读性依赖于良好的编码风格: 如果没有良好的缩进习惯,Bash 脚本的可读性会大大降低。
  • 容易出错: 由于没有强制缩进,容易出现代码块界限模糊的问题,导致逻辑错误。

示例:

1
2
3
4
5
6
7
#!/bin/bash

if [ $VAR -gt 10 ]; then
echo "VAR is greater than 10"
else
echo "VAR is not greater than 10"
fi

运维开发工程师的实践建议

作为运维开发工程师,你需要熟练掌握 Python 和 Bash 脚本,并根据具体情况选择合适的语言:

  • Python: 适合处理复杂逻辑、数据处理、以及需要更高效代码的场景。
  • Bash: 适合执行简单的系统管理任务、快速编写 shell 脚本以及与系统命令交互。

无论使用哪种语言,良好的代码风格和一致的缩进都是至关重要的。 对于 Python,严格遵守强制缩进规则;对于 Bash,即使没有强制要求,也应该养成良好的缩进习惯以提高代码的可读性和可维护性。 这将有助于提高你的工作效率,并减少代码错误。

总结

Python 的强制缩进和 Bash 脚本的灵活语法代表了两种不同的编程范式。 理解这两种语言的差异,并根据实际需求选择合适的语言和编码风格,对于运维开发工程师至关重要。 记住,无论使用哪种语言,清晰、一致的代码风格都是编写高质量代码的关键。

Awk 模式详解及运维实战案例

Awk 是一款强大的文本处理工具,在系统运维工作中被广泛用于日志分析、数据统计等任务。熟练掌握 Awk 的模式匹配和处理能力,可以极大地提高工作效率。本文将详细介绍 Awk 的常用模式,并结合实际运维场景,提供具体的案例分析。

1. BEGIN { statements }

说明: BEGIN 模式中的语句在 Awk 程序开始处理输入数据之前执行一次。通常用于初始化变量、打印表头等操作。

运维例子: 统计日志文件中的 IP 地址访问次数,并在结果之前打印表头。

1
awk 'BEGIN { print "IP 地址\t请求次数" } { count[$1]++ } END { for (ip in count) print ip, count[ip] }' access.log

这个例子中,BEGIN 块打印表头,后续处理每一行日志,统计每个 IP 地址的访问次数,最后在 END 块中打印结果。

2. END { statements }

说明: END 模式中的语句在 Awk 程序处理完所有输入数据之后执行一次。通常用于打印汇总信息、统计结果等。

运维例子: 统计某个日志文件中总行数。

1
awk 'END { print "总共行数:", NR }' access.log

NR 是 Awk 的内置变量,表示当前处理的行号。END 块在处理完所有行后打印 NR 的值,即总行数。

3. expression { statements }

说明:expression 表达式的值为真 (非零或非空字符串) 时,执行 statements 中的语句。

运维例子: 筛选出状态码为 500 的错误请求。

1
awk '$9 == 500 { print $0 }' access.log

假设 access.log 的第九个字段是状态码,该命令将打印所有状态码为 500 的行。

4. /正则表达式/ { statements }

说明: 当输入行匹配指定的正则表达式时,执行 statements 中的语句。

运维例子: 查找所有包含 “error” 字样的日志行。

1
awk '/error/ { print $0 }' /var/log/syslog

该命令将打印 /var/log/syslog 中所有包含 “error” 的行。

5. 复合模式 (Compound Pattern)

说明: 使用逻辑运算符 && (与)、|| (或)、! (非) 组合多个条件进行匹配。

运维例子: 筛选出来自 192.168.1.0/24 网段且状态码为 404 的访问记录。

1
awk '$1 ~ /^192\.168\.1\.[0-9]{1,3}/ && $9 == 404 { print $0 }' access.log

这个例子筛选出 IP 地址匹配 192.168.1.0/24 网段并且状态码为 404 的日志行。

6. 范围模式 (Range Pattern)

说明: pattern1, pattern2 { statements } 当输入行从匹配 pattern1 开始到匹配 pattern2 结束 (包含 pattern1pattern2 行) 的所有行都执行 statements

运维例子: 提取 /var/log/messages 中特定时间段的日志内容。

1
awk '/Oct 26 10:00:00/,/Oct 26 10:10:00/ { print $0 }' /var/log/messages

这个例子提取从 “Oct 26 10:00:00” 到 “Oct 26 10:10:00” 之间的所有日志行。

总结

熟练运用 Awk 的各种模式,可以高效地处理各种文本数据,尤其在日志分析、数据统计等运维工作中非常实用。 理解这些模式的用法,并结合实际场景进行练习,才能真正掌握 Awk 的强大功能。

Awk 代码风格指南:提升可读性和可维护性

Awk 是一种强大的文本处理工具,其简洁的语法使得它能够高效地处理各种文本数据。然而,为了保证代码的可读性和可维护性,良好的代码风格至关重要。本文将介绍一些 Awk 代码风格方面的最佳实践,帮助你编写更清晰、更易于理解的 Awk 脚本。

1. 空行的作用

在 Awk 代码中,空行会被忽略,不会影响程序的执行。 合理地使用空行可以有效地分隔不同的逻辑块,提高代码的可读性。

1
2
3
{ print $1 }

{ print $2 }

以上代码中,空行将两个 print 语句分隔开来,使代码结构更加清晰。

2. 空格和制表符的灵活运用

在 Awk 中,空格和制表符 (Tab) 可以灵活地用于操作符和操作数之间,不会影响程序的运行结果。 合理的空格和制表符的使用可以使代码更美观、更易读。

1
2
3
{ print $1,$2 }       # 紧凑型写法
{ print $1, $2 } # 加了空格
{ print $1 , $2 } # 加了多个空格

选择哪种风格取决于个人偏好,但保持一致性非常重要。

3. 注释的必要性

使用注释来解释代码的作用,特别是对于复杂的逻辑或不直观的代码段。 注释以 # 开头,到行尾结束。

1
{ print $1, $3 }   # 打印第一列和第三列数据

良好的注释可以大大提高代码的可理解性和可维护性。

4. 长语句的换行处理

如果一行代码过长,可以使用反斜杠 \ 将其断开到下一行。 反斜杠必须放在你希望换行的位置,并且反斜杠后不能有多余的空格。

1
2
3
{ print $1, \
$2, \
$3 }

这使得长语句更易于阅读和理解。

总结

Awk 代码不要求写得过于紧凑。 适当使用空行、空格、注释和换行符,可以极大地提高代码的可读性和可维护性。 选择一种代码风格并坚持使用,将有助于提高团队合作效率和代码质量。 记住,清晰易懂的代码比简洁紧凑的代码更重要,尤其是在团队协作和长期维护的项目中。


Awk 语法要点:模式与动作的书写规范

Awk 是一种强大的文本处理工具,其简洁的语法使得它能够高效地处理各种文本数据。然而,这种简洁性也意味着对语法规则的严格遵守。本文将重点介绍 Awk 中模式和动作的书写规范,特别是关于左花括号 { 的位置要求。

模式与动作的结构

Awk 脚本的核心在于其模式-动作语句结构。模式定义了匹配条件,动作则指定了匹配成功后执行的操作。 其基本结构如下:

pattern { action }

其中:

  • pattern: 匹配模式,可以是正则表达式、条件表达式或空(表示对所有行执行动作)。
  • action: 动作,由花括号 {} 包裹的一系列 Awk 语句。

左花括号 { 的位置要求

Awk 语法对模式和动作的书写格式有一定要求,尤其是在左花括号 { 的位置。关键规则是:动作的左花括号必须与它的模式在同一行。

正确的写法:

1
/regex/ { print $1 }  # 左花括号与模式在同一行

或者:

1
2
3
4
/regex/ {
print $1
print $2
} # 右花括号可以另起一行

在以上两种写法中,左花括号都与模式 /regex/ 在同一行。 动作部分可以跨越多行,但左花括号必须紧跟在模式之后,在同一行。

错误的写法:

1
2
3
4
/regex/
{
print $1
} # 左花括号与模式不在同一行,这是错误的

这种写法会导致语法错误。 Awk 解释器无法正确识别模式和动作之间的关系。

为什么有此规定?

这种语法规则是为了避免歧义。如果允许左花括号另起一行,Awk 解释器将难以判断模式和动作的边界,容易造成语法错误。 这种简洁的语法设计,保证了 Awk 代码的清晰性和可解析性。

总结:

编写 Awk 脚本时,务必将左花括号 { 与前面的模式写在同一行。 这不仅是语法要求,也是为了提高代码的可读性和可维护性。 遵守这个简单的规则,可以避免许多不必要的错误,提高开发效率。

Awk 脚本编写:灵活的语句组织方式

Awk 是一种强大的文本处理工具,其简洁的语法和灵活的语句组织方式使得它能够高效地处理各种文本数据。本文将重点介绍 Awk 脚本中语句的组织方式,并通过示例说明其灵活性和便捷性。

Awk 脚本的核心在于其模式-动作语句结构。模式定义了匹配条件,动作则指定了匹配成功后执行的操作。 一个关键的特性是,Awk 允许灵活地组织这些动作语句,这使得脚本编写更加简洁或易于阅读。

语句组织方式:

Awk 脚本中的动作语句可以采用以下两种方式组织:

  1. 每行一条语句 (常规写法): 这是最常见也是最易读的方式。每条语句占据一行,清晰地展现了程序的逻辑流程。

    1
    2
    3
    4
    {
    print $1 # 打印第一列
    print $NF # 打印最后一列
    }
  2. 一行多条语句 (使用分号): 为了提高代码的紧凑性,可以将多条语句写在同一行,用分号 ; 分隔。这在处理简单的操作时尤其方便。

    1
    { print $1; print $NF; }

    上述代码与第一种方式的效果完全相同,只是将两条语句写在了同一行。

分号的灵活使用:

在语句的末尾添加多余的分号不会导致错误。Awk 会忽略这些多余的分号。

1
{ print $1; print $NF;; }  # 最后一个分号被忽略

示例:处理国家数据

假设我们有一个名为 countries 的文件,内容如下:

1
2
3
4
France 211 55 Europe
Japan 144 120 Asia
Germany 96 61 Europe
England 94 56 Europe

我们想打印每个国家的名称和所属的大洲。可以使用以下两种 Awk 脚本:

方法一 (每行一条语句):

1
2
3
4
{
print $1
print $4
}

方法二 (一行多条语句):

1
{ print $1; print $4; }

两种方法的输出结果都相同:

1
2
3
4
5
6
7
8
France
Europe
Japan
Asia
Germany
Europe
England
Europe

总结:

Awk 提供了灵活的语句组织方式,既支持每行一条语句的清晰风格,也支持一行多条语句的紧凑风格。 使用分号分隔多条语句可以使代码更简洁,而多余的分号不会影响程序的执行。选择哪种方式取决于程序的复杂性和个人偏好,关键在于保持代码的可读性和可维护性。 合理运用这些特性,可以编写出更有效率和易于理解的 Awk 脚本。

Nginx状态码详解:运维和开发的责任边界

Nginx作为一款高性能的Web服务器和反向代理服务器,在处理客户端请求的过程中会返回各种HTTP状态码,这些状态码对于快速定位问题,区分运维和开发的责任至关重要。本文将对常见的Nginx状态码进行详细解释,并明确指出哪些问题归属于运维,哪些问题归属于开发。

1xx 信息性状态码

这类状态码表示请求已被接收,继续处理。在实际应用中,1xx状态码很少见,通常不会直接返回给客户端。

2xx 成功状态码

这类状态码表示请求已成功被服务器接收、理解和处理。

  • 200 OK: 请求成功,这是最常见的成功响应。

3xx 重定向状态码

这类状态码表示客户端浏览器需要采取进一步的操作才能完成请求。

  • 301 Moved Permanently: 永久重定向,通常用于URL重写,表示资源已永久移动到新的URL。
  • 302 Found: 临时重定向,也常用于重写规则,但表示资源只是临时移动到新的URL。
  • 304 Not Modified: 请求的资源内容没有改变,服务器返回304状态码,浏览器会使用缓存中的资源。这对于提高性能和减少服务器负载非常有效。

4xx 客户端错误状态码 (运维的锅)

这类状态码表示客户端发出的请求有错误。 这些问题通常由客户端或Nginx的配置引起,因此责任通常在运维团队。

  • 400 Bad Request: 错误请求,表示服务器无法理解客户端的请求。这可能是由于客户端发送了格式错误的请求,例如请求参数不完整或格式错误。 通常是运维需要检查Nginx配置或客户端请求是否正确。
  • 401 Unauthorized: 未授权,表示客户端没有权限访问请求的资源。这通常是因为客户端没有提供有效的身份验证信息,例如缺少或无效的API Key或会话令牌。 运维需要检查Nginx身份验证配置是否正确。
  • 403 Forbidden: 禁止访问,表示服务器理解客户端的请求,但拒绝执行它。这可能是由于服务器配置、权限设置或其他限制导致的。 运维需要检查Nginx的访问控制配置是否正确。
  • 404 Not Found: 未找到,表示服务器找不到客户端请求的资源。这可能是由于URL错误、文件不存在或资源被删除。 运维需要检查文件路径、Nginx配置以及服务器文件系统。

5xx 服务器错误状态码 (开发的锅)

这类状态码表示服务器在处理请求时发生了错误。 这些问题通常由服务器端代码或后端服务引起的,因此责任通常在开发团队。

  • 500 Internal Server Error: 服务器内部错误,表示服务器遇到意外情况,无法完成请求。这通常是由于服务器端代码出现异常、数据库错误或其他内部问题导致的。 开发需要检查服务器端代码,排查异常和错误。
  • 502 Bad Gateway: 错误网关,通常出现在反向代理场景中,表示Nginx无法从后端服务器获取有效的响应。这可能是由于后端服务器宕机、超时或返回错误响应导致的。 开发需要检查后端服务器的运行状态和响应。运维也需要检查Nginx和后端服务器之间的连接配置。
  • 503 Service Unavailable: 服务不可用,表示服务器暂时无法处理请求,通常由于服务器维护、过载或其他原因导致。 开发需要检查服务器资源是否充足,并优化代码以提高性能。运维也需要监控服务器资源并采取相应的措施。

总结:

通过分析HTTP状态码,我们可以快速判断问题所在,并明确运维和开发团队的责任。 记住,这只是一个通用的指导,实际情况可能需要更深入的调查和分析。 良好的监控和日志记录对于快速定位和解决问题至关重要。

Nginx 模块划分及配置文件参数详解

Nginx 是一款高性能的 Web 服务器,其配置文件 nginx.conf 决定了服务器的行为。本文将详细解释 Nginx 配置文件的模块划分,并对每个模块中的重要参数进行说明。

Nginx 配置文件结构

Nginx 配置文件通常由四个主要的模块组成:maineventshttpstream。 这些模块层层嵌套,形成一个清晰的层次结构。

1. main 模块:全局配置

main 模块包含 Nginx 服务器的全局配置参数,这些参数影响整个服务器的运行。 示例代码片段中,main 模块包含以下参数:

  • worker_processes: 指定 Nginx 工作进程的数量。这个值决定了服务器能够同时处理的请求数量。 值越高,并发能力越强,但同时也增加了系统资源的消耗。 示例代码中设置为 1,仅用于测试或低负载环境。生产环境中需要根据服务器资源进行调整。

  • error_log: 指定 Nginx 错误日志的路径和级别。 示例中为 logs/error.log,表示错误日志将记录到 logs 目录下的 error.log 文件中。

  • pid: 指定 Nginx 进程 ID (PID) 文件的路径。 这个文件记录了 Nginx 主进程的 PID,方便进程管理。

2. events 模块:事件处理

events 模块配置 Nginx 的事件处理机制,影响服务器的并发处理能力。 示例代码中包含:

  • worker_connections: 每个工作进程能够同时处理的最大连接数。 示例中设置为 1024,这是一个相对较小的值,生产环境中需要根据服务器资源和预期负载进行调整。

3. http 模块:HTTP 服务配置

http 模块是 Nginx 配置文件中最重要的部分,它包含了所有与 HTTP 服务相关的配置。 它包含多个 server 块,每个 server 块定义一个虚拟服务器。 示例中 http 模块包含:

  • include mime.types;: 包含 MIME 类型配置文件,用于指定不同文件扩展名的 MIME 类型。

  • default_type application/octet-stream;: 设置默认的 MIME 类型,当无法根据文件扩展名确定 MIME 类型时使用。

  • sendfile on;: 启用 sendfile 系统调用,提高文件传输效率。

  • keepalive_timeout 65;: 设置持久连接的超时时间 (单位:秒)。

4. server 块:虚拟服务器配置

server 块位于 http 块内,每个 server 块定义一个虚拟服务器,可以监听不同的端口,并配置不同的域名和路径。 示例代码中包含一个 server 块:

  • listen 80;: 监听 80 端口 (HTTP 默认端口)。

  • server_name localhost;: 设置服务器名称,此处为 localhost,表示只监听本地请求。

  • root /html;: 设置网站根目录。

  • index index.html index.htm;: 设置默认首页文件。

  • error_page 500 502 503 504 /50x.html;: 配置自定义错误页面。

5. location 块:URI 路径匹配

location 块位于 server 块内,用于匹配特定的 URI 路径,并对匹配的请求进行不同的处理。 示例代码中未显示 location 块,但它在 Nginx 配置中非常重要,用于实现 URL 重写、反向代理等功能。

6. stream 模块:TCP/UDP 代理

stream 模块用于配置 TCP/UDP 代理,处理非 HTTP 协议的流量。 本示例中未涉及。

总结

本文简要介绍了 Nginx 配置文件的模块划分和关键参数。 要深入理解 Nginx 的配置,还需要参考官方文档并进行实践。 希望本文能帮助你更好地理解 Nginx 配置文件。

简述什么是 Nginx

Nginx (engine x) 是一款轻量级、高性能的 HTTP 和反向代理服务器,同时也提供 IMAP/POP3/SMTP 服务。它以其高并发处理能力、快速响应速度和低资源消耗而闻名。

Nginx 的主要特点

  • 高并发: Nginx 基于异步非阻塞的事件驱动模型 (epoll),能够同时处理数万甚至数十万个并发连接,有效提高服务器的吞吐量。

  • 响应快: 尤其在处理静态文件方面,Nginx 的响应速度非常快,这得益于其高效的 sendfile 系统调用。

  • 热部署: Nginx 支持热部署,主要体现在两个方面:

    • 平滑升级: 可以不中断服务的情况下升级 Nginx 版本。
    • 快速重载配置: 修改配置文件后,无需重启 Nginx 即可生效。
  • 高可靠: Nginx 使用 master-worker 架构,master 进程负责管理 worker 进程,worker 进程负责处理实际请求。即使某个 worker 进程崩溃,也不会影响整个服务器的运行。

  • 分布式支持: Nginx 作为反向代理服务器,可以实现七层负载均衡,将请求分发到不同的后端服务器,提高系统的可用性和可扩展性。新版本也支持四层负载均衡。

  • 低消耗: Nginx 资源占用少,即使处理数万个并发请求,其内存占用也相对较低 (例如,处理 1 万个请求,内存占用可能仅为 2~3 MB)。

Nginx 的应用场景

  1. Web 服务器软件: Nginx 可以作为独立的 Web 服务器,与 Apache、IIS、lighttpd 等同类软件竞争。

  2. 邮件代理服务器: Nginx 提供了 IMAP/POP3/SMTP 服务,可以作为邮件服务器使用。

  3. 反向代理服务器: Nginx 作为反向代理服务器,可以实现负载均衡 (Load Balance),将客户端请求分发到多个后端服务器,提高系统的性能和可靠性。

Nginx 反向代理示意图

总结

Nginx 是一款功能强大且高效的服务器软件,广泛应用于各种 Web 应用场景,其高性能、高可靠性和易用性使其成为许多大型网站和应用的首选服务器软件。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

0%