开发容器:可重用的开发环境(开发容器:可重用的开发环境是指)
nanshan 2024-11-10 10:14 23 浏览 0 评论
什么是开发容器
当我们说到“容器”,通常指的是使用 Docker 运行的容器。这也意味着项目可以在 Linux 环境中。当今的大多数 Web 应用程序开发都是这样的。但如果你的项目目标是 iOS,或 Windows 桌面,或其他非 Unix 平台,那么下面的内容可能不太适用于你的项目。
这不是一篇介绍 Docker 的文章。由于篇幅的原因,我将假设你对容器化有一定的了解。
不过,我们还是有必要简单地讨论一下为什么容器比一些老旧的虚拟化技术(如 Parallels、VirtualBox 或 Vagrant)更适合作为开发环境。
简单地说,这是因为容器并不是虚拟化的。是的,容器为我们提供了一种看起来像是运行在电脑上的微型电脑的东西。但容器并没有试图模拟计算机,而是通过创建一组独立的命名空间来发挥作用,包括文件系统命名空间、网络端口、进程表和运行操作系统所需的其他命名空间。
与虚拟化不同,容器有可能按照原生的速度运行项目代码和工具,而不会让开发机器瘫痪。因为宿主操作系统可以将文件映射到容器命名空间,所以我们可以在容器运行代码的同时使用原生工具编辑源代码。
另外,与大多数虚拟化技术不同的是,容器并不是不透明的二进制镜像。我们使用人类可读的配置文件来决定开发容器将包含哪些 Linux 版本、系统包和库、实用程序、文件系统映射、开放端口和支持服务,而且这些配置文件与项目的源代码一起进行版本控制。
实际上,开发容器是一种功能齐全的开发环境,它可以被共享、进行版本控制、可重复使用、自动文档化,并且只要在使用中,它就是最新的。开发容器就像拉面:只要加入热水就可以吃了。
本文也不是教程。构建一个完整的开发容器是一个持续迭代的过程,取决于具体的项目。相反,我将向读者介绍什么是开发容器、开发容器的使用,以及借助开发容器为团队构建可重用的开发环境是一种怎样的体验。
体验开发容器
为什么说容器是开发环境的未来?让我们来看一些可以体现开发容器优势的例子。
快速上手
最近,我加入了一个为期 6 个月的客户项目。像大多数开发大型旧项目的团队一样,他们在 README 和 Wiki 页上有一系列冗长的初始设置说明和脚本。和往常一样,部分指南的内容要么过时,要么自相矛盾。设置脚本的前提是它们要运行在一台特定时期推出的 MacBook 上,需要安装特定版本的 MacOS,并且这台笔记本将专门用于这个项目的开发。
这种令人困惑的、冗长的、过时的初始设置是我见过的大多数团队的常态。在加入项目的第一周,如果你能够运行项目的一部分测试套件,就算很好了!
在我加入这个团队的第一个项目中,我创建了一个开发容器配置,将所有这些文档的内容转化为可执行的配置。
为此,我创建了一些专门的 Docker 配置文件,与用于创建部署容器的 Docker 配置文件分开。它们位于项目代码库的.devcontainer 目录中。
.devcontainer/
├── Dockerfile
├── README.md
├── devcontainer-load-profile.sh
├── devcontainer.json
├── docker-compose.yml
├── entrypoint.sh
├── init-once.sh
├── init.sh
└── profile.sh
复制代码
这里通常会包含一个 docker-compose 配置文件,定义了要启动哪些容器,以及它们如何相互连接并连接到宿主。
version: "3.2"
services:
app:
user: developer
build:
context: .
dockerfile: Dockerfile
volumes:
- type: bind
source: ..
target: /workspace
- type: bind
source: ${HOME}${USERPROFILE}/.ssh
target: /home/developer/.ssh
working_dir: /workspace
command: sleep infinity
environment:
BUNDLE_PATH: vendor/bundle
INTERFACE: "0.0.0.0"
ports:
- "3000:3000"
复制代码
通常还有一个 Dockerfile 文件,用于定制应用程序开发容器。
FROM ruby:2.7.2
RUN apt-get update \
&& apt-get install -y yarnpkg vim lsof \
&& ln -s /usr/bin/yarnpkg /usr/local/bin/yarn \
&& rm -rf /var/lib/apt/lists/*
COPY sixmilebridge-load-profile.sh /etc/profile.d/
ARG USERNAME=developer
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME
复制代码
如果我们使用的是 VS Code,可以配置 devcontainer.json 文件。开发容器里还会有一些脚本文件,在容器生命周期的各个阶段发挥作用。
.devcontainer/
├── Dockerfile
├── README.md
├── devcontainer-load-profile.sh
├── devcontainer.json
├── docker-compose.yml
├── entrypoint.sh
├── init-once.sh
├── init.sh
└── profile.sh
复制代码
在完成这个开发容器的定义后,我就把它全部提交到项目代码库中。
一开始,团队中的一些人说:“我们永远不会用它……你忙你的!”
然后,一件有趣的事情发生了。一些新员工用了开发容器,很快就上手开发了。来自另一个团队的一些人用开发容器在他们通常不参与的代码库上创建 PR,再也不需要花一周时间去设置开发环境了。慢慢地,开发容器已经成为我最受夸赞的贡献之一。
使用开发容器最明显和最直接的好处之一是简化了项目启动流程,而且并不只是对新员工来说是这样的,甚至连前端团队的员工都能够参与调整后端的应用程序代码。这可能意味着,在三年后,你能够快速修复 Bug。
共享基础工具
项目的配置检查清单和脚本很快就会过时,因为一旦我们在一台机器上设置好了项目,就会把它们忘得一干二净。而开发容器会定期进行重新构建。开发容器是可执行的文档,它包含了项目日常开发使用的库、服务、系统配置、开放端口、实用工具等。
例如,你的团队是否会使用 ngrok 将本地开发的机器开发给远程用户?不要把这个设置说明些什么 Wiki 页上,而是将它添加到开发容器中。
RUN wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip \
&& unzip ngrok-stable-linux-amd64.zip \
&& mv ngrok /usr/local/bin \
&& rm ngrok-stable-linux-amd64.zip
复制代码
这样,所有使用开发容器的人都能在需要时获取到合适的工具。
vscode ? /workspace (main ?) $ ngrok --version
ngrok version 2.3.40
复制代码
任何人都可以随时运行所有的测试
在很多项目中,如果你能在本地运行单元测试,就会被认为做得很好——但只有 CI 系统能够提供运行集成测试所需的支持服务。在极端情况下,只有少数基础设施人员知道如何在系统测试失败时修复它们,而开发人员在这个时候却什么也做不了。
每个人都可以共享开发容器,也可以在 CI 中使用,我们可以提升我们的期望:每个人都可以随时运行所有的测试。虽然它们在 CI 管道中可能执行地更快,但保持集成测试通过率变成了每个人的事情。
开发容器能够为整个测试周期提供支持,因为它们能打包所有东西,不仅包括用于开发应用程序的虚拟微型计算机,还包括运行应用程序所需的支持服务。应用程序需要 Redis 服务器和安装了特定扩展的特定版本的 PostgreSQL?docker-compose 配置文件可以确保在开发容器启动时,这些组件都是可用的。
它甚至可以将 Postgres 专家对数据库的优化变成编码,这些优化可以提升开发数据库的响应性而非可靠性。
redis:
image: redis:${REDIS_VERSION:-6.0.9}
postgres:
image: mdillon/postgis:${POSTGRES_VERSION:-9.6}
command: ["-c", "fsync=off", "-c", "full_page_writes=off", "-c", "synchronous_commit=off"]
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
复制代码
在项目之间进行干净的切换
说到这里,你是否曾经安装过特定的系统库或者 PostgreSQL 版本来满足一个应用程序,结果却破坏了你正在开发的另一个应用程序?有了开发容器,你就可以在一台机器上的多个项目之间进行干净的切换。这对于顾问来说是必不可少的,但也适用于任何拥有多个项目代码库的组织。
说到项目切换,如果你习惯使用 Python、Ruby 或 JavaScript 等编程语言,就习惯了使用 VirtualEnv、RVM 或 NVM 等版本管理器。这些工具可以同时构建、安装和管理多个版本的 Python、Ruby 或 Node,并确保每个项目使用正确的语言运行时版本。在这个过程中,它们增加了一个额外的间接层。它们会成为一个麻烦,因为当你需要应对一个你不熟悉的语言生态系统时,它们可能会成为生产力障碍。
开发容器消除了对这些工具的依赖。因为一个开发容器专门用于一个项目,所以它可以全局安装指定版本的 Ruby、Python 或 JavaScript。如果运行时是从源代码编译的,那就可以将其整合到开发容器的 Dockerfile 文件中。自从我开始使用开发容器以来,还没有用过语言版本管理器,而且我并不怀念它们!
共享快捷技巧
随着时间的推移,许多项目团队发展出了一套“标准”的 shell 和 git 别名,缩短了常见操作命令的长度。其中一些是基本的别名,适用于所有项目,但有一些与一个团队如何开发应用程序有关。
alias gs="git status"
alias be="bundle exec"
复制代码
通常情况下,这些东西由团队中的某些人分享出来,然后其他人慢慢采用它们。他们先是匹配代码,然后发现他们习惯使用的快捷技巧并不存在,这可能会令人感到不快。
这些快捷技巧的存在或不存在也可能导致团队微妙地分化为“酷孩子”(他们总是有最好的 shell 别名)和“不酷的孩子”。
如果任何人都可以立即为其他人添加有用的东西 shell 别名,会怎样?这个时候使用开发容器就能做到。我们不用在 Slack 中发布 shell 别名的清单,而是创建一个 PR,演示如何在 Slack 中使用它们。因为开发容器包含了一个共享的设备 UNIX 用户空间,所以你可以确保这些快捷技巧对每个人都有效。
更有效地调试
开发容器还提供了一些不太明显的好处。根据定义,容器是一个高度可控的环境,就像是显微镜下有一个微小的计算机网络。本文没有足够的篇幅来详细讨论,但我想说得是,开发容器让调试变得更加容易:监控应用程序的文件写入、网络 I/O,甚至是系统调用,这样就可以准确地了解它在干什么。
重现问题
当团队中的大多数人都在使用开发容器时,它的最大好处就会显现出来。你是否曾经遇到过团队中某个开发人员突然遇到了别人都没注意到的问题?最终,在进行了大量的故障排除之后,发现他收到的系统更新与项目所依赖的某个库不兼容。没有人知道怎样帮助他,因为其他人的电脑上没有这个问题!
开发容器可以大大减少这种“在我的电脑上没问题”的现象。没有什么东西可以保持每个开发人员的开发环境完全相同,但一个公共的容器定义可以消除大量潜在的变化。在知道了是哪个库更新破坏了项目,就可以很容易地修复它。因为在使用容器时,你可以根据需要获取工具和系统库的版本。
在云端编码
在有了开发容器的定义后,你就不局限于在“我的机器”上开发了!
使用 Gitpod 、Amazon Cloud 9 、 JetBrains Space 或 GitHub Codespaces 等工具进行基于云的开发已经成为一种趋势,而且这种趋势只会越来越明显。
基于云的开发环境支持远程结对编程。只要有浏览器,你就能够在任何地方编写代码,即使你不小心把手提电脑包忘在火车上了。如果你有一个可以在本地执行的开发容器定义,也可以用它在云端启动一个 IDE。
开发容器也非常适用于开源工作。你有没有想过为开源项目做一点小小的贡献?但是,在拉取代码时,你意识到运行单元测试需要一个漫长而复杂的设置过程。于是,你放弃了,只能在他们的问题追踪器里提了个建议。
如果开源项目附带的开发容器可以立即提升业余贡献者的生产力,那会怎样?这可能会更容易吸引到业余贡献者!
VS Code 中的开发容器
让我们来讨论一下编辑器和 IDE。
IDE 开始添加一些特性来支持基于容器的开发。微软的开源编辑器 VS Code 绝对是这一趋势的领头羊。事实上,我对开发容器的很多想法,包括“开发容器”这个术语,都是受 VS Code 提供容器支持的方式的启发。越来越多的编辑器和 IDE 都添加了容器感知功能。
开发容器与支持开发容器的 IDE 的紧密集成可以帮助开发人员在开始项目时提升效率。例如,现在的项目中一般都会有针对代码库定制的 Lint 或格式化规则。在以前,新加入的开发人员需要自己安装 Lint 工具,并确保编辑器做了正确的配置。有了容器感知的编辑器配置,开发人员在第一次启动项目时 Lint 和代码格式化就已经可用了。
这并不是说开发容器就这样将你与使用完全相同的编辑器配置锁定在一起了。事实并非如此!例如,在使用 VS Code 时,开发容器可以包含一个基础的特定于项目的设置和插件,但你也可以在此基础上添加自己的设置、插件、配色方案、按键映射等。
这并不是说团队就只能使用一种编辑器。一个项目可以有支持多个支持开发容器的 IDE 的配置。你可以在开发容器中包含完整的 VIM 设置,包括编辑器本身!
开发容器不是部署容器
现在,没有什么工具或技术是万能的。稍后我将讨论一些你可能不想使用开发容器的情况。但在此之前,我想分享关于使用开发容器的一个最大的转折点。
我经常会听到这样的建议:“我们已经有了容器定义,为什么不能重用它?”或者完全相反:“开发容器这个东西并不适合我们,因为我们没有使用容器来部署我们的应用程序。”
我认为这两个观点都有同一个错误的前提:容器是用来部署的。这种误解是可以理解的。如果你已经在项目中使用了容器,这可能是因为这是你部署应用程序的一种方式。你甚至可能在持续集成基础设施中使用了容器。容器不就是用来装东西的吗?
的确,使用容器来部署应用程序是促进容器普及的一个应用场景。但是,不管你是否用容器来部署应用程序,开发容器都很有用!事实上,如果你只是将开发容器视为部署容器,会很容易错过它强大的功能。
事情是这样的:用于部署的容器与用于开发的容器有着非常不同的需求。事实上,针对部署容器的许多要求几乎与开发容器完全相反。
我们希望部署容器尽可能地小和精简。我们希望它们精简、快速和安全。这意味着要尽量减少不必要的库和工具,所以尽量使用基础镜像,如 Debian Slim,甚至是 Alpine Linux,它们去掉了普通 Linux 发行版中常见的 glibc 库。但是对于开发容器来说,它们需要提供一个完整、舒适的开发环境。这意味着一个像 Ubuntu 这样的 Linux 发行版,需要包含命令行工具、编译器、帮助文档和整个工具包!
对于部署,你希望最小化安全横截面。对于开发,你需要打开更多的端口来支持调试!对于部署,不得不与 Honeycomb 或 New Relic 这样的可观测服务通信。对于开发,你不希望向这些服务发送消息,你可能希望“伪造”或模拟一些外部服务。在部署过程中,你想要减少 Docker 构建的层数,而在开发过程中,你可能希望在不需要完全重建镜像的情况下快速添加增量的变更。
在很多方面,部署容器和开发容器的目标是相互对立的。这就是为什么当我面对一个新客户并开始构建一个开发容器时,通常会从头开始。我会构建一套全新的容器配置文件,从项目设置指令而不是从已有的 Dockerfile 开始。这为我提供了一个可移植的、可复制的开发环境,但不是为了部署。
但这并不意味着开发容器和部署容器的配置就不能共享一些共同的部分。因为本文的篇幅所限,这里不能再展开描述了。不过这里有一个提示:你可以从开发容器开始,并将其简化为部署容器,这比从部署容器开始并将其变成开发环境要容易得多。
关于开发容器的注意事项
综上所述,开发容器并不适用于所有项目。
我们所讨论的一切都是基于用 Docker 运行的容器。目前,大多数 Web 和企业应用程序都部署在基于 Linux 的服务器上,因此使用开发容器就等于是在接近生产环境的环境中做开发。Android 开发也是如此。但是,如果你的部署目标不是 Linux 或类似 Linux 的系统,你可能就不会想这么做。如果你的目标是 iOS 设备或 Windows 桌面,那么容器开发可能不是最佳选择。
此外,到 2021 年,基于 Docker 的桌面开发平台已经有了明显的发展。
在基于 Linux 的机器上运行 Docker 可能有着最好的体验,因为 Linux 是容器的原生主机。
但令人感到惊讶的是,现在的次优选择是 Windows。这是因为随着 Windows 的 Linux 子系统 2(或“WSL2”)的出现,Windows 现在可以原生运行 Linux。实际上,你可以直接从 Windows 存储库中选择你需要的 Linux 发行版,并直接从 Debian 或 Fedora 存储库中运行 Linux 二进制文件,不需要进行任何重新编译或模拟。
Docker Desktop on Windows 使用 WSL2 作为后端。这意味着 Windows 上的 Docker 容器可以有效地运行在原生 Linux 环境中,没有虚拟化性能损失。在我的使用过程中,它们很稳定,能够以原生的速度运行 Rails 项目。
MacOS 是以 BSD 为基础构建的,并不是 Linux,而且它没有与 WSL2 等价的工具。这意味着为了运行 Docker,需要进行一定程度的虚拟化。我不再用 Mac 做开发,但我从朋友那里听说,他们在使用 Docker 时遇到了一些古怪的问题,尤其是在文件 I/O 方面。
这该怎么办呢?幸运的是,这是一个众所周知的问题,Docker 和苹果公司都有意要去解决。事实上,在我写这篇文章时,Docker 宣布了一些针对 MacOS 性能的重大更新。如果幸运的话,这个问题将很快成为本文最过时的部分!
我们在容器里写代码
有一些技术,一旦成熟了,就会永久地改变技术的发展状态。
在我编程时,版本控制还没有被普遍接受。一些项目仍然通过定期压缩的代码副本来记录历史。在我后来的职业生涯中,版本控制变得越来越普遍。然后,持续集成从一种新颖的想法变成了一种行业标准。现在,分布式版本控制和持续集成成了桌面开发的筹码:我们几乎无法想象没有它们的软件项目会是什么样子。
2021 年,我们正处于容器发展的拐点。五年后,我们会对过去认为在第一次提交代码之前花几天时间安装开发者笔记本电脑是多么正常的事情而嗤之以鼻。但你不需要等那么久,只要稍加努力,你就可以让自己和团队从开发容器中获得好处。
你可以有一个可移植的、可复制的开发环境,它可以跟随你从一台机器搬到另一台机器,甚至到云端。你可以在一小时内让新员工上手,而不是几天。你可以更容易地为开源项目做出贡献。你可以确保在 CI 系统中运行的每一个测试也都可以在本地运行。你可以通过 GitHub 与你的队友分享你的开发配置和脚本。你可以通过将开发容器作为项目开发工作流程的一部分来实现这一切。
结论
所以,这就是为什么我认为你应该放下一切,为你当前的项目创建一个开发容器定义。不仅如此,你还应该使用开发容器并完善它,直到它变得像家一样舒适。
相关推荐
- Centos7虚拟机安装及网络配置(二)
-
#二、centos7的网络配置-Nat模式NAT模式也是VMware创建虚拟机的默认网络连接模式。使用NAT模式网络连接时,VMware会在主机上建立单独的专用网络,用以在主机和虚拟机之间相互通信。虚...
- 网络分析shell脚本(实时流量+连接统计)
-
介绍一个强大的分析网络的shell脚本,此脚本是从EZHTTP拆分出来的,觉得有必要单独介绍下。脚本运行效果截图:此脚本包含的功能有:1、实时监控任意网卡的流量2、统计10秒内平均流量3、统计每个端口...
- Centos之Could not retrieve mirrorlist解决方案
-
Centos之Couldnotretrievemirrorlist解决方案:vi/etc/sysconfig/network-scripts/ifcfg-你的网卡名字修改:ONBOOT=ye...
- 一文掌握!VirtualBox 中 Rock9.x(Linux)网络配置全攻略
-
一、前言记得我有一篇文章《必看!VirtualBox中Centos7(Linux)网络配置全攻略》讲的非常明细,但是因为CentOS已经停止维护了,可能很多人都不想继续学CentOS,我也是一样,...
- CentOS 6.0 设置IP地址、网关、DNS
-
在做任何操作之前先备份原文件,我们约定备份文件的名称为:源文件名称+bak,例如原文件名称为:centos.txt那么备份文件名称为:centos.txtbak引言:linux的网卡IP地址是存放在文...
- Linux CentOS 基础操作(centos怎么操作)
-
简介:养成学习Linux的好习惯,第一是多查看manpage(manual)等帮助文档和利用好Tab键;第二是掌握好一些快捷键,比如ctrl+c(停止当前进程),ctrl+r(查看命令历史)...
- Linux抓包王者技能!这条命令直接封神,教你精准定位网络问题
-
在网络故障排查和性能调优中,抓包是一项必不可少的技能。对于Linux环境下的网络工程师和运维人员来说,掌握高效抓包方法至关重要。而要说“抓包界的王炸”,那非tcpdump莫属!今天,我们不仅要介绍...
- 「干货」如何在 Linux 上划分VLAN?
-
在某些场景中,我们希望在Linux服务器(CentOS/RHEL)上的同一网卡分配来自不同VLAN的多个ip。这可以通过启用VLAN标记接口来实现,但要实现这一点,首先必须确保交换机上添加多个vl...
- CentOS 8 网络配置实战教程:静态IP、路由与DNS设置
-
一、配置前准备1.查看当前网络信息#查看所有网络接口nmclidevicestatus#查看指定网卡信息(假设网卡名为ens192)ipaddrshowens192#查看路由...
- Debian10.7修改网络配置(debian怎么配置网络)
-
简介:关于Debian获取IP地址的方法主要有两种,动态获取和静态设置。在配置网络之前先要知道Debian的网卡名称是什么,Debian可通过命令#ipa查看网卡名称。本文主要通过介绍Debian...
- 巧用SSH转发功能深入穿透内网(ssh转发udp)
-
ssh能够提供客户端到服务端的加密传输,当http、ftp等协议被防火墙所拦截时,可以考虑使用SSH的端口转发功能,将其它TCP端口的网络数据通过SSH连接来转发。转发方式一共有三种,分别是:动态转发...
- CentOS Linux 7 的IP地址配置(centos7.4配置ip地址)
-
前段时间有位朋友,在一台PC机上安装了CentOSLinux7系统,因为要接入局域网,需要配置IP地址和默认网关信息。于是参照一本Linux教程上编辑网卡配置信息的方法,输入:vim/etc/s...
- 教你如何在 Linux 上划分VLAN(linux怎么分区详解)
-
在某些场景中,我们希望在Linux服务器(CentOS/RHEL)上的同一网卡分配来自不同VLAN的多个ip。这可以通过启用VLAN标记接口来实现,但要实现这一点,首先必须确保交换机上添加多个vl...
- 打通数据高速公路:如何在 CentOS 上使用 Thunderbolt 3 和 4
-
Thunderbolt3与4是现代高速外设连接的代表,带来了40Gbps的惊人带宽,支持数据、视频、音频与供电的“四合一”功能,尤其在专业视频编辑、科研计算、虚拟化扩展等领域具有巨大价值...
- VMware 虚拟机 CentOS7 桥接模式静态 IP 配置全攻略
-
虚拟机桥接模式原理配置成桥接网络连接模式的虚拟机就当作主机所在以太网的一部分,虚拟系统和宿主机器的关系,就像连接在同一个Hub上的两台电脑,可以像主机一样可以访问以太网中的所有共享资源和网络连接,可以...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
手机如何设置与显示准确时间的详细指南
-
【系统配置】信创终端挂载NAS共享全攻略:一步到位!
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
- 最近发表
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)