2个小时1.5w字| React & Golang 全栈微服务实战

目录

  • 前言
  • [Golang 入门教程](#Golang 入门教程)
    • [1. 下载与环境配置](#1. 下载与环境配置)
      • [安装 Go](#安装 Go)
        • [Windows 安装](#Windows 安装)
        • [macOS 安装](#macOS 安装)
        • [Linux 安装](#Linux 安装)
      • [理解 GOROOT 和 GOPATH](#理解 GOROOT 和 GOPATH)
        • GOROOT
        • GOPATH
        • [Go Modules 与 GOPATH 的关系](#Go Modules 与 GOPATH 的关系)
        • [查看和设置 Go 环境变量](#查看和设置 Go 环境变量)
      • [配置 GOPATH](#配置 GOPATH)
    • [2. 语法与包管理](#2. 语法与包管理)
    • 扩展练习
  • [Kratos 微服务框架入门](#Kratos 微服务框架入门)
    • [1. Kratos 核心介绍](#1. Kratos 核心介绍)
      • [1.1 核心理念](#1.1 核心理念)
      • [1.2 主要特性](#1.2 主要特性)
      • [1.3 设计架构](#1.3 设计架构)
    • [2. 项目初始化方法](#2. 项目初始化方法)
      • [2.1 安装 Kratos 命令行工具](#2.1 安装 Kratos 命令行工具)
      • [2.2 创建新项目](#2.2 创建新项目)
      • [2.3 添加 API 定义](#2.3 添加 API 定义)
      • [2.4 生成 API 代码](#2.4 生成 API 代码)
    • [3. CLI 工具详解](#3. CLI 工具详解)
      • [3.1 主要命令](#3.1 主要命令)
      • [3.2 Proto 相关命令](#3.2 Proto 相关命令)
      • [3.3 工具依赖](#3.3 工具依赖)
    • [4. 依赖注入](#4. 依赖注入)
      • [4.1 Wire 基础](#4.1 Wire 基础)
      • [4.2 Provider 定义](#4.2 Provider 定义)
      • [4.3 Wire 注入点](#4.3 Wire 注入点)
      • [4.4 生成注入代码](#4.4 生成注入代码)
    • [5. 项目结构详解](#5. 项目结构详解)
      • [5.1 标准目录结构](#5.1 标准目录结构)
      • [5.2 各目录职责](#5.2 各目录职责)
    • [6. 项目运行链路分析](#6. 项目运行链路分析)
      • [6.1 启动流程](#6.1 启动流程)
      • [6.2 请求处理流程](#6.2 请求处理流程)
      • [6.3 HTTP服务示例](#6.3 HTTP服务示例)
      • [6.4 完整服务架构](#6.4 完整服务架构)
    • 扩展阅读与资源
  • [React 入门教程](#React 入门教程)
  • [Next.js 入门教程](#Next.js 入门教程)
  • 容器知识入门教程
  • 全栈博客案例

前言

本文分为6个小节,带你全方位入门 React & Golang 微服务全栈开发。

  1. golang
  2. kratos
  3. react
  4. next.js
  5. docker
  6. 博客案例

每一个小节均有丰富的代码案例,仓库地址如下:https://github.com/BaiZe1998/go-learning

Golang|AI 主题知识星球:白泽说 试运营当中,添加 wx:baize_talk02 咨询,免费加入。

Golang 入门教程

1. 下载与环境配置

安装 Go

Windows 安装

  1. 访问 Go 官方下载页面
  2. 下载 Windows 安装包 (MSI)
  3. 运行安装程序,按照提示完成安装
  4. 安装完成后,打开命令提示符,输入 go version 确认安装成功

macOS 安装

  1. 访问 Go 官方下载页面
  2. 下载 macOS 安装包 (PKG)
  3. 运行安装程序,按照提示完成安装
  4. 或者使用 Homebrew: brew install go
  5. 安装完成后,打开终端,输入 go version 确认安装成功

Linux 安装

  1. 访问 Go 官方下载页面

  2. 下载对应的 Linux 压缩包

  3. 解压到 /usr/local

    bash 复制代码
    sudo tar -C /usr/local -xzf go1.x.x.linux-amd64.tar.gz
  4. 添加环境变量到 ~/.profile~/.bashrc

    bash 复制代码
    export PATH=$PATH:/usr/local/go/bin
  5. 使环境变量生效:source ~/.profilesource ~/.bashrc

  6. 验证安装:go version

理解 GOROOT 和 GOPATH

GOROOT

GOROOT 是 Go 语言的安装目录,它包含了 Go 标准库、编译器、工具等。安装 Go 时会自动设置这个环境变量。

  • 作用:告诉 Go 工具链在哪里可以找到 Go 的标准库和工具

  • 默认位置

    • Windows: C:\go
    • macOS/Linux: /usr/local/go 或 Homebrew 安装位置
  • 查看 GOROOT

    bash 复制代码
    go env GOROOT
  • 手动设置(通常不需要,除非安装在非标准位置):

    • Windows: 添加系统环境变量 GOROOT=C:\path\to\go
    • macOS/Linux: 在 ~/.profile~/.bashrc 中添加 export GOROOT=/path/to/go

GOPATH

GOPATH 是 Go 的工作目录,用于存放 Go 代码、包和依赖等。

  • 作用

    • 在 Go Modules 出现前(Go 1.11之前),所有 Go 项目必须位于 GOPATH 内
    • 在 Go Modules 时代,GOPATH 主要用于存储下载的依赖包和编译后的二进制文件
  • 默认位置

    • Windows: %USERPROFILE%\go (例如:C:\Users\YourName\go)
    • macOS/Linux: $HOME/go (例如:/home/username/go/Users/username/go)
  • GOPATH 目录结构

    • src: 存放源代码(如你的项目和依赖包的源码)
    • pkg: 存放编译后的包文件
    • bin: 存放编译后的可执行文件
  • 设置多个 GOPATH

    可以设置多个目录,用冒号(Unix)或分号(Windows)分隔

    bash 复制代码
    # Unix/macOS
    export GOPATH=$HOME/go:$HOME/projects/go
    
    # Windows
    set GOPATH=%USERPROFILE%\go;D:\projects\go

Go Modules 与 GOPATH 的关系

从 Go 1.11 开始,Go 引入了 Go Modules 作为官方的依赖管理解决方案,逐渐弱化了 GOPATH 的作用:

  • Go Modules 模式下

    • 项目可以位于任何目录,不必在 GOPATH 内
    • 依赖通过 go.mod 文件管理,而不是通过 GOPATH 目录结构
    • 下载的依赖缓存在 $GOPATH/pkg/mod 目录
    • 编译的命令仍安装到 $GOPATH/bin
  • 环境变量 GO111MODULE

    • GO111MODULE=off: 禁用模块支持,使用 GOPATH 模式
    • GO111MODULE=on: 启用模块支持,忽略 GOPATH
    • GO111MODULE=auto: 在 GOPATH 内禁用模块支持,在 GOPATH 外启用模块支持

查看和设置 Go 环境变量

bash 复制代码
# 查看所有 Go 环境变量
go env

# 查看特定环境变量
go env GOPATH
go env GOROOT

# 设置环境变量(Go 1.14+)
go env -w GOPATH=/custom/path

配置 GOPATH

GOPATH 是工作目录,用于存放 Go 代码、包和依赖等:

  1. 创建 GOPATH 目录,例如:mkdir -p $HOME/go
  2. 设置环境变量:
    • Windows: 添加 GOPATH 系统环境变量,值为你创建的目录路径
    • macOS/Linux: 在 ~/.profile~/.bashrc 中添加 export GOPATH=$HOME/go
  3. GOPATH 目录结构:
    • src: 源代码
    • pkg: 包文件
    • bin: 可执行文件

2. 语法与包管理

Go 基础语法

查看 hello.go 文件了解 Go 的基本语法,包括:

  • 包声明与导入
  • 变量声明与使用
  • 基本数据类型
  • 控制流(条件语句、循环)
  • 函数定义与调用
  • 切片与数组操作

运行 Go 程序

bash 复制代码
go run hello.go

构建 Go 程序

bash 复制代码
go build hello.go
./hello  # 运行编译后的可执行文件

包管理 (Go Modules)

从 Go 1.11 开始,Go 引入了 Go Modules 作为官方的依赖管理解决方案:

  1. 初始化一个新模块:

    bash 复制代码
    go mod init example.com/myproject
  2. 添加依赖:

    bash 复制代码
    go get github.com/some/dependency
  3. 整理和更新依赖:

    bash 复制代码
    go mod tidy
  4. 查看所有依赖:

    bash 复制代码
    go list -m all

常用标准库

  • fmt: 格式化输入输出
  • io: 基本 I/O 接口
  • os: 操作系统功能
  • net/http: HTTP 客户端和服务器
  • encoding/json: JSON 编解码
  • time: 时间相关功能
  • sync: 同步原语

推荐学习资源

扩展练习

  1. 修改 hello.go 添加更多功能
  2. 创建一个简单的 HTTP 服务器
  3. 实现文件读写操作
  4. 使用 Go 实现一个简单的 CLI 工具

Kratos 微服务框架入门

Kratos 是一个轻量级的、模块化的、可插拔的Go微服务框架,专注于帮助开发人员快速构建微服务。本教程将带你深入了解 Kratos 的核心概念和使用方法。

1. Kratos 核心介绍

Kratos 是哔哩哔哩开源的一款Go微服务框架,具有以下核心特点:

1.1 核心理念

  • 简洁:提供了简洁、统一的接口定义和使用方式
  • 模块化:各个组件可独立使用,也可组合使用
  • 可扩展:支持各类中间件和插件的扩展
  • 高性能:追求极致的性能优化

1.2 主要特性

  • 传输层:支持 HTTP 和 gRPC 服务,并提供统一抽象
  • 中间件:丰富的内置中间件,如日志、指标、跟踪、限流等
  • 注册发现:支持多种服务注册与发现机制
  • 配置管理:灵活的配置加载和动态配置
  • 错误处理:统一的错误处理和错误码管理
  • API定义:使用 Protocol Buffers 作为 API 定义语言
  • 依赖注入:使用 Wire 进行依赖管理和注入

1.3 设计架构

Kratos 采用领域驱动设计 (DDD) 的六边形架构,将应用分为以下层次:

  • API层:定义服务接口,通常使用Proto文件
  • Service层:处理服务业务逻辑的实现
  • Biz层:核心业务逻辑和领域模型
  • Data层:数据访问层,负责与持久化存储交互
  • Server层:传输层,提供HTTP/gRPC服务

2. 项目初始化方法

Kratos 提供了完善的项目初始化流程,帮助开发者快速创建项目骨架。

2.1 安装 Kratos 命令行工具

bash 复制代码
# 安装最新版本的 Kratos 命令行工具
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest

2.2 创建新项目

bash 复制代码
# 创建名为 myproject 的新项目
kratos new myproject

# 进入项目目录
cd myproject

2.3 添加 API 定义

bash 复制代码
# 创建 API 文件
kratos proto add api/myproject/v1/myproject.proto

2.4 生成 API 代码

在编写完 proto 文件后,使用 kratos 命令生成相应代码:

bash 复制代码
# 生成客户端代码
kratos proto client api/myproject/v1/myproject.proto

# 生成服务端代码
kratos proto server api/myproject/v1/myproject.proto -t internal/service

3. CLI 工具详解

Kratos CLI 是 Kratos 框架的命令行工具,提供了丰富的功能帮助开发者提高效率。

3.1 主要命令

命令 说明 用法示例
new 创建新项目 kratos new myproject
proto 管理 Proto 文件与代码生成 kratos proto add/client/server
run 运行项目 kratos run
build 构建项目 kratos build
upgrade 更新 Kratos 工具 kratos upgrade

3.2 Proto 相关命令

bash 复制代码
# 添加新的 proto 文件
kratos proto add api/helloworld/v1/greeter.proto

# 生成 client 代码
kratos proto client api/helloworld/v1/greeter.proto

# 生成 server 代码
kratos proto server api/helloworld/v1/greeter.proto -t internal/service

# 生成所有代码
kratos proto all api/helloworld/v1/greeter.proto -t internal/service

3.3 工具依赖

使用 Kratos 相关功能需要安装以下组件:

bash 复制代码
# 安装 protoc 编译器依赖
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2@latest

4. 依赖注入

Kratos 使用 Wire 框架进行依赖注入,实现了组件的松耦合和代码的可测试性。

4.1 Wire 基础

Wire 是 Google 开发的编译时依赖注入工具,通过代码生成而非反射实现依赖注入。

4.2 Provider 定义

在 Kratos 中,各个组件通过 Provider 函数提供实例:

go 复制代码
// data层 provider
func NewData(conf *conf.Data, logger log.Logger) (*Data, func(), error) {
    // 实例化数据层
    cleanup := func() {
        // 清理资源
    }
    return &Data{}, cleanup, nil
}

// biz层 provider
func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase {
    return &GreeterUsecase{repo: repo}
}

// service层 provider
func NewGreeterService(uc *biz.GreeterUsecase, logger log.Logger) *GreeterService {
    return &GreeterService{uc: uc}
}

4.3 Wire 注入点

cmd/server/wire.go 中定义依赖注入:

go 复制代码
// ProviderSet 是各层的依赖集合
var ProviderSet = wire.NewSet(
    data.ProviderSet,
    biz.ProviderSet,
    service.ProviderSet,
    server.ProviderSet,
)

// 应用实例化函数
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, error) {
    panic(wire.Build(ProviderSet, newApp))
}

4.4 生成注入代码

bash 复制代码
# 生成依赖注入代码
cd cmd/server
wire

5. 项目结构详解

Kratos 项目结构遵循 DDD 六边形架构,组织清晰。

5.1 标准目录结构

复制代码
├── api                    # API 定义目录 (protobuf)
│   └── helloworld
│       └── v1
│           └── greeter.proto
├── cmd                    # 应用程序入口
│   └── server
│       ├── main.go
│       ├── wire.go        # 依赖注入
│       └── wire_gen.go    # 自动生成的依赖注入代码
├── configs                # 配置文件目录
│   └── config.yaml
├── internal               # 私有应用代码
│   ├── biz                # 业务逻辑层 (领域模型)
│   │   ├── biz.go
│   │   └── greeter.go
│   ├── conf               # 配置处理代码
│   │   ├── conf.proto
│   │   └── conf.pb.go
│   ├── data               # 数据访问层 (持久化)
│   │   ├── data.go
│   │   └── greeter.go
│   ├── server             # 传输层(HTTP/gRPC)
│   │   ├── server.go
│   │   ├── http.go
│   │   └── grpc.go
│   └── service            # 服务实现层
│       └── greeter.go
├── third_party            # 第三方 proto 文件
└── go.mod

5.2 各目录职责

  1. api: 定义服务 API 接口,使用 Protocol Buffers
  2. cmd: 程序入口,包含 main 函数和依赖注入
  3. configs: 配置文件
  4. internal : 私有代码,不对外暴露
    • biz: 核心业务逻辑,包含领域模型和业务规则
    • data: 数据访问层,实现数据库操作和缓存
    • server: 服务器定义,包括 HTTP 和 gRPC 服务器配置
    • service: 服务实现,连接 API 和业务逻辑
  5. third_party: 第三方依赖的 proto 文件

6. 项目运行链路分析

Kratos 应用从启动到处理请求的完整流程。

6.1 启动流程

  1. 初始化配置:加载 configs 目录的配置文件
  2. 依赖注入:通过 Wire 构建应用依赖关系
  3. 创建服务器:初始化 HTTP/gRPC 服务器
  4. 注册服务:注册 API 实现
  5. 启动服务:启动服务监听
go 复制代码
// main.go 中的启动流程
func main() {
    // 1. 初始化 logger
    logger := log.NewStdLogger(os.Stdout)
    
    // 2. 加载配置
    c := config.New(config.WithSource(file.NewSource(flagconf)))
    if err := c.Load(); err != nil {
        panic(err)
    }
    
    // 3. 通过依赖注入创建 app 实例
    app, cleanup, err := wireApp(c, logger)
    if err != nil {
        panic(err)
    }
    defer cleanup()
    
    // 4. 启动应用
    if err := app.Run(); err != nil {
        panic(err)
    }
}

6.2 请求处理流程

HTTP 请求从接收到响应的完整流程:

  1. 接收请求:HTTP/gRPC 服务器接收请求
  2. 中间件处理:请求经过中间件链(日志、跟踪、限流等)
  3. 路由匹配:根据路径匹配对应处理器
  4. 参数解析:解析和验证请求参数
  5. 服务层处理:Service 层实现请求处理
  6. 业务逻辑:调用 Biz 层的领域逻辑
  7. 数据访问:通过 Data 层访问数据库或缓存
  8. 响应构建:构建响应数据
  9. 中间件后处理:响应经过中间件链
  10. 返回响应:返回给客户端

6.3 HTTP服务示例

以下是一个简化的 HTTP 服务示例:

go 复制代码
import (
    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/log"
    "github.com/go-kratos/kratos/v2/middleware/recovery"
    "github.com/go-kratos/kratos/v2/transport/http"
)

func main() {
    // 初始化 logger
    logger := log.NewStdLogger(os.Stdout)
    
    // 创建 HTTP 服务器
    httpSrv := http.NewServer(
        http.Address(":8000"),
        http.Middleware(
            recovery.Recovery(), // 异常恢复中间件
        ),
    )
    
    // 注册路由
    r := httpSrv.Route("/")
    r.GET("/hello", func(ctx http.Context) error {
        return ctx.String(200, "Hello Kratos!")
    })
    
    // 创建 Kratos 应用
    app := kratos.New(
        kratos.Name("example"),
        kratos.Server(httpSrv),
        kratos.Logger(logger),
    )
    
    // 启动应用
    if err := app.Run(); err != nil {
        log.Error(err)
    }
}

6.4 完整服务架构

在实际项目中,请求处理链路涉及多个组件和层次:

复制代码
客户端 → 负载均衡 → HTTP/gRPC服务器 → 中间件链 → 路由 → Service层 → Biz层 → Data层 → 数据库/缓存
             ↑                                                             ↓
服务注册/发现 ← ←  ←  ←  ←  ←  ←  ←  ←  ←  ←  ←  ←  ← 响应  ←  ←  ←  ←  ← ←

扩展阅读与资源

React 入门教程

React 是由 Facebook 开发的一个用于构建用户界面的 JavaScript 库。React 使开发人员能够构建快速、可扩展的 Web 应用程序。

1. 下载与环境配置

要开始使用 React,您需要一个现代的 JavaScript 环境和 Node.js 开发环境。

安装 Node.js 和 pnpm

首先,安装 Node.js(包含 npm):

  • Windows/macOS : 从 Node.js 官网 下载并安装
  • macOS (使用 Homebrew) : brew install node
  • Linux : sudo apt install nodejs npmsudo yum install nodejs npm

验证安装:

bash 复制代码
node -v

然后安装 pnpm (性能更好的包管理器):

bash 复制代码
# 使用npm安装pnpm
npm install -g pnpm

# 验证pnpm安装
pnpm --version

创建新的 React 应用

使用 Create React App 工具创建新的 React 应用:

bash 复制代码
# 创建新项目
pnpm create react-app my-react-app

# 进入项目目录
cd my-react-app

# 启动开发服务器
pnpm start

或者使用 Vite 创建(更快的启动速度,推荐):

bash 复制代码
# 使用 Vite 创建 React 项目
pnpm create vite my-react-app --template react

# 进入项目目录
cd my-react-app

# 安装依赖
pnpm install

# 启动开发服务器
pnpm dev

2. React 基本语法与包管理

基本概念

  1. 组件 (Components):React 应用由组件构成

    • 函数组件(推荐)
    • 类组件
  2. JSX:JavaScript 的语法扩展,允许在 JS 中编写类似 HTML 的代码

  3. Props:向组件传递数据的方式

  4. State:组件的内部状态

  5. Hooks:在函数组件中使用状态和其他 React 特性的 API

函数组件示例

jsx 复制代码
import React from 'react';

function Greeting(props) {
  return <h1>你好,{props.name}!</h1>;
}

export default Greeting;

使用 State Hook

jsx 复制代码
import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>你点击了 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>
        点击我
      </button>
    </div>
  );
}

使用 Effect Hook

jsx 复制代码
import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(seconds => seconds + 1);
    }, 1000);
    
    return () => clearInterval(interval);
  }, []);

  return <div>计时器:{seconds} 秒</div>;
}

包管理与依赖

React 项目使用 pnpm 管理依赖(pnpm比npm和yarn更快、更高效):

bash 复制代码
# 安装依赖
pnpm add react-router-dom

# 安装开发依赖
pnpm add -D typescript @types/react

# 更新所有依赖
pnpm update

# 运行脚本
pnpm run dev

pnpm的主要优势:

  • 磁盘空间高效:pnpm使用内容寻址存储来避免重复安装
  • 快速安装:比npm和yarn快2-3倍
  • 严格的依赖管理:更好的避免依赖地狱问题
  • 支持monorepo:内置对工作空间的支持

常用的包:

  • react-router-dom: 路由管理
  • axios: HTTP 请求
  • zustandredux-toolkit: 状态管理
  • styled-componentsemotion: CSS-in-JS 解决方案
  • MUIAnt Design: UI 组件库

本目录代码示例说明

本目录包含两个主要文件:

  1. App.jsx: 包含三个示例组件

    • 计数器:展示基本的状态管理
    • 计时器:展示 useEffect 的使用
    • 待办事项列表:展示更复杂的状态管理
  2. App.css: 为组件提供样式

如何运行示例代码

要运行本示例,需要将这些文件集成到一个 React 项目中:

  1. 创建新的 React 应用:

    bash 复制代码
    pnpm create vite react-demo --template react
    cd react-demo
    pnpm install
  2. 替换 src/App.jsxsrc/App.css 为本目录中的文件

  3. 启动应用:

    bash 复制代码
    pnpm dev

pnpm 常用命令参考

bash 复制代码
# 初始化新项目
pnpm init

# 安装依赖
pnpm add [package]

# 安装开发依赖
pnpm add -D [package]

# 全局安装
pnpm add -g [package]

# 运行脚本
pnpm [script]

# 移除依赖
pnpm remove [package]

# 更新依赖
pnpm update

# 查看过时依赖
pnpm outdated

学习资源

练习建议

  1. 修改计数器组件,添加最大值和最小值限制
  2. 为待办事项添加优先级功能
  3. 添加一个新的表单组件,练习表单处理
  4. 尝试使用 Context API 在组件之间共享状态

Next.js 入门教程

Next.js 是一个基于 React 的轻量级框架,用于构建静态和服务器渲染的应用程序。它提供了丰富的功能,如服务器端渲染、静态网站生成、API 路由、自动代码分割等。本教程基于 Next.js 13+ 的 App Router。

1. 项目目录与优雅实践

Next.js 项目结构 (App Router)

一个典型的 Next.js 项目结构如下:

复制代码
my-nextjs-app/
│
├── app/               # App Router 目录(基于文件约定的路由)
│   ├── layout.tsx     # 根布局组件
│   ├── page.tsx       # 首页 (/)
│   ├── about/         # 关于页面路由
│   │   └── page.tsx   # 关于页面 (/about)
│   ├── blogs/         # 博客路由
│   │   ├── [id]/      # 动态路由
│   │   │   └── page.tsx # 博客文章页面 
│   │   ├── new/       # 创建新博客
│   │   │   └── page.tsx # 创建博客页面
│   │   └── page.tsx   # 博客列表页面 
│   ├── api/           # API 路由
│   │   └── route.ts   # API 处理器 
│   ├── globals.css    # 全局样式
│   └── error.tsx      # 错误处理页面
│
├── components/        # React 组件
│   ├── ui/            # UI 组件
│   └── ClientComponent.tsx # 客户端组件示例
│
├── lib/               # 工具函数和库
│   └── utils.ts
│
├── public/            # 静态资源
│   ├── favicon.ico    
│   └── images/
│
├── .next/             # Next.js 构建输出 (git ignored)
├── node_modules/      # 依赖 (git ignored)
├── package.json       # 项目依赖和脚本
├── pnpm-lock.yaml     # pnpm 锁文件
├── next.config.js     # Next.js 配置
├── tsconfig.json      # TypeScript 配置
└── README.md          # 项目说明

Next.js App Router 优雅实践

  1. 文件系统路由约定

    • app/page.tsx/ (首页)
    • app/about/page.tsx/about (关于页面)
    • app/blogs/[id]/page.tsx/blogs/:id (动态路由)
    • 特殊文件:
      • layout.tsx: 布局组件
      • loading.tsx: 加载状态
      • error.tsx: 错误处理
      • not-found.tsx: 404页面
  2. 数据获取方法

    • React Server Components 中的直接获取
    • generateStaticParams: 静态路径生成
    • revalidatePath/revalidateTag: 按需重新验证
    • 客户端数据获取: SWR 或 React Query
  3. API 路由

    • app/api/*/route.ts 文件定义 API 端点
    • 使用 NextResponse 进行响应处理
  4. 布局系统

    • 嵌套布局
    • 平行路由和拦截路由
    • 模板和分组
  5. 渲染策略

    • 服务器组件(默认)
    • 客户端组件 ('use client')
    • 流式渲染和部分渲染

2. 快速启动案例前端

安装 Node.js 和 pnpm

首先,确保你已安装 Node.js 和 pnpm:

bash 复制代码
# 安装 pnpm (如果尚未安装)
npm install -g pnpm

# 验证安装
pnpm --version

创建 Next.js 项目

使用 pnpm 创建新的 Next.js 项目:

bash 复制代码
# 使用 create-next-app 创建TypeScript项目
pnpm create next-app my-nextjs-app --typescript

# 进入项目目录
cd my-nextjs-app

在创建项目过程中,会提示你选择一些选项。请确保选择 "Yes" 当询问是否使用 App Router 时。

项目结构设置

默认情况下,create-next-app 生成的项目已经包含基本结构。您可以根据需要添加额外的目录。

创建首页

首页是访问者首先看到的页面,在 app/page.tsx 文件中创建:

tsx 复制代码
// app/page.tsx
import Link from 'next/link';

export default function Home() {
  return (
    <div className="container mx-auto px-4 py-8">
      <section className="py-12 text-center">
        <h1 className="text-4xl font-bold mb-4">欢迎来到我的博客</h1>
        <p className="text-lg text-gray-600 mb-8">探索技术、设计和创意的世界</p>
        <Link 
          href="/blog" 
          className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
        >
          浏览博客文章
        </Link>
      </section>
      
      <section className="py-8">
        <h2 className="text-2xl font-bold mb-6 text-center">最新文章</h2>
        <div className="grid md:grid-cols-3 gap-6">
          <div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
            <h3 className="text-xl font-semibold mb-3">Next.js入门指南</h3>
            <p className="text-gray-600 mb-4">了解如何使用Next.js构建现代Web应用</p>
            <Link href="/blog/1" className="text-blue-600 hover:underline">
              阅读更多 &rarr;
            </Link>
          </div>
          <div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
            <h3 className="text-xl font-semibold mb-3">React服务器组件详解</h3>
            <p className="text-gray-600 mb-4">深入理解React服务器组件的工作原理</p>
            <Link href="/blog/2" className="text-blue-600 hover:underline">
              阅读更多 &rarr;
            </Link>
          </div>
          <div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
            <h3 className="text-xl font-semibold mb-3">TypeScript与Next.js</h3>
            <p className="text-gray-600 mb-4">如何在Next.js项目中充分利用TypeScript</p>
            <Link href="/blog/3" className="text-blue-600 hover:underline">
              阅读更多 &rarr;
            </Link>
          </div>
        </div>
      </section>
      
      <section className="py-8">
        <h2 className="text-2xl font-bold mb-6 text-center">关于客户端组件</h2>
        <div className="border rounded-lg p-6">
          <p className="text-gray-700 mb-4">
            Next.js的App Router架构区分<strong>服务器组件</strong>和<strong>客户端组件</strong>。
            默认情况下,所有组件都是服务器组件,在服务器上渲染并发送到客户端。
          </p>
          <p className="text-gray-700 mb-4">
            当需要使用浏览器API、添加交互性或使用React hooks时,应该使用客户端组件。
            通过在文件顶部添加 <code className="bg-gray-100 px-2 py-1 rounded">'use client'</code> 指令来声明客户端组件。
          </p>
          <div className="bg-gray-50 p-4 rounded-lg">
            <h3 className="font-semibold mb-2">客户端组件示例:</h3>
            <pre className="bg-gray-800 text-white p-4 rounded overflow-x-auto">
              <code>{`'use client'

import { useState, useEffect } from 'react'

export default function ClientComponent() {
  const [count, setCount] = useState(0)
  
  return (
    <div>
      <h3>计数器: {count}</h3>
      <button onClick={() => setCount(count + 1)}>
        增加
      </button>
    </div>
  )
}`}</code>
            </pre>
          </div>
        </div>
      </section>

      <section className="py-8">
        <h2 className="text-2xl font-bold mb-6 text-center">功能演示</h2>
        <div className="grid md:grid-cols-2 gap-6">
          <div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
            <h3 className="text-xl font-semibold mb-3">博客列表</h3>
            <p className="text-gray-600 mb-4">查看使用服务器组件和模拟数据实现的博客列表页面</p>
            <Link href="/blog" className="text-blue-600 hover:underline">
              查看示例 &rarr;
            </Link>
          </div>
          <div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
            <h3 className="text-xl font-semibold mb-3">客户端组件</h3>
            <p className="text-gray-600 mb-4">了解如何在Next.js中使用客户端组件实现交互功能</p>
            <Link href="/client-example" className="text-blue-600 hover:underline">
              查看示例 &rarr;
            </Link>
          </div>
        </div>
      </section>
    </div>
  );
}

首页包含了以下元素:

  • 欢迎区域,包含标题和指向博客列表的链接
  • 最新文章区域,展示最近的博客文章

创建页面

app 目录中创建 page.tsx 文件以添加新页面:

tsx 复制代码
// app/about/page.tsx
export default function AboutPage() {
  return (
    <div>
      <h1>关于我们</h1>
      <p>这是 Next.js 示例项目的关于页面。</p>
    </div>
  )
}

创建布局

使用 layout.tsx 文件创建布局:

tsx 复制代码
// app/layout.tsx
import type { ReactNode } from 'react';

interface RootLayoutProps {
  children: ReactNode;
}

export default function RootLayout({ children }: RootLayoutProps) {
  return (
    <html lang="zh">
      <body>
        <header>
          <nav>
            {/* 导航栏组件 */}
          </nav>
        </header>
        <main>{children}</main>
        <footer>© {new Date().getFullYear()} 我的 Next.js 应用</footer>
      </body>
    </html>
  )
}

创建动态路由

使用方括号语法创建动态路由:

tsx 复制代码
// app/blogs/[id]/page.tsx
import { notFound } from 'next/navigation';
import Link from 'next/link';

// 模拟博客数据
const blogPosts = [
  { 
    id: '1', 
    title: 'Next.js入门指南',
    content: `
      <p>Next.js是一个基于React的强大框架,它提供了许多内置功能,使得构建现代Web应用变得更加简单。</p>
      <h2>主要特性</h2>
      <ul>
        <li>服务器端渲染 (SSR)</li>
        <li>静态站点生成 (SSG)</li>
        <li>API路由</li>
        <li>文件系统路由</li>
        <li>内置CSS和Sass支持</li>
        <li>代码分割和打包优化</li>
      </ul>
      <p>使用Next.js,你可以快速开发出高性能的React应用,无需复杂的配置。</p>
    `,
    author: {
      name: '张三',
      avatar: 'https://randomuser.me/api/portraits/men/1.jpg'
    },
    publishedAt: '2023-05-15',
    tags: ['Next.js', 'React', '前端开发']
  },
  { 
    id: '2', 
    title: 'React服务器组件详解',
    content: `
      <p>React服务器组件是React的一项新特性,它允许开发者创建在服务器上渲染的组件,从而提高性能并减少客户端JavaScript的体积。</p>
      <h2>服务器组件的优势</h2>
      <ol>
        <li>减少客户端JavaScript包大小</li>
        <li>直接访问服务器资源(数据库、文件系统等)</li>
        <li>自动代码分割</li>
        <li>改善首次加载性能</li>
      </ol>
      <p>在Next.js的App Router中,所有组件默认都是服务器组件,除非你显式声明为客户端组件。</p>
    `,
    author: {
      name: '李四',
      avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
    },
    publishedAt: '2023-06-22',
    tags: ['React', '服务器组件', '性能优化']
  },
  { 
    id: '3', 
    title: 'TypeScript与Next.js',
    content: `
      <p>TypeScript是JavaScript的超集,添加了静态类型检查,在Next.js项目中使用TypeScript可以带来诸多好处。</p>
      <h2>TypeScript的优势</h2>
      <ul>
        <li>静态类型检查,减少运行时错误</li>
        <li>更好的IDE支持,包括代码补全和智能提示</li>
        <li>更容易维护的代码库</li>
        <li>自文档化的代码</li>
      </ul>
      <h2>在Next.js中使用TypeScript</h2>
      <p>Next.js原生支持TypeScript,你可以直接创建.tsx或.ts文件,无需额外配置。</p>
      <p>对于页面和API路由,你可以使用TypeScript接口来定义props和请求参数的类型。</p>
    `,
    author: {
      name: '王五',
      avatar: 'https://randomuser.me/api/portraits/men/3.jpg'
    },
    publishedAt: '2023-07-10',
    tags: ['TypeScript', 'Next.js', '类型安全']
  }
];

// 获取博客帖子函数
const getBlogPost = (id: string) => {
  return blogPosts.find(post => post.id === id);
};

// 博客详情页面组件
export default function BlogPostPage({ params }: { params: { id: string } }) {
  const post = getBlogPost(params.id);
  
  // 如果没有找到文章,返回404
  if (!post) {
    notFound();
  }
  
  return (
    <div className="container mx-auto px-4 py-8">
      <article className="max-w-3xl mx-auto">
        <div className="mb-8">
          <Link href="/blog" className="text-blue-600 hover:underline mb-4 inline-block">
            &larr; 返回博客列表
          </Link>
          <h1 className="text-4xl font-bold mb-4">{post.title}</h1>
          
          <div className="flex items-center mb-6">
            <img 
              src={post.author.avatar} 
              alt={post.author.name}
              className="w-10 h-10 rounded-full mr-3"
            />
            <div>
              <p className="font-medium">{post.author.name}</p>
              <p className="text-gray-500 text-sm">发布于 {post.publishedAt}</p>
            </div>
          </div>
          
          <div className="flex flex-wrap gap-2 mb-8">
            {post.tags.map(tag => (
              <span key={tag} className="bg-blue-100 text-blue-800 text-sm px-3 py-1 rounded-full">
                {tag}
              </span>
            ))}
          </div>
        </div>
        
        <div 
          className="prose prose-lg max-w-none"
          dangerouslySetInnerHTML={{ __html: post.content }}
        />
        
        <div className="mt-12 pt-8 border-t border-gray-200">
          <h3 className="text-xl font-bold mb-4">分享这篇文章</h3>
          <div className="flex space-x-4">
            <button className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
              分享到微信
            </button>
            <button className="px-4 py-2 bg-blue-400 text-white rounded hover:bg-blue-500">
              分享到微博
            </button>
          </div>
        </div>
      </article>
    </div>
  );
} 

创建 API 路由

app/api 目录中创建 API 端点:

ts 复制代码
// app/api/hello/route.ts
// app/api/route.ts
import { NextRequest, NextResponse } from 'next/server'

// 模拟用户数据
const users = [
  { id: '1', name: '张三', email: '[email protected]' },
  { id: '2', name: '李四', email: '[email protected]' },
  { id: '3', name: '王五', email: '[email protected]' }
];

export async function GET() {
  return NextResponse.json({ 
    success: true,
    data: users,
    timestamp: new Date().toISOString()
  })
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    
    // 验证请求数据
    if (!body.name) {
      return NextResponse.json(
        { success: false, error: '名称不能为空' },
        { status: 400 }
      )
    }
    
    // 模拟创建新用户
    const newUser = {
      id: (users.length + 1).toString(),
      name: body.name,
      email: body.email || null
    }
    
    // 在真实应用中,这里会将用户添加到数据库
    // 这里只是模拟
    
    return NextResponse.json({ 
      success: true, 
      data: newUser 
    }, { status: 201 })
  } catch (error) {
    return NextResponse.json(
      { success: false, error: '请求处理失败' },
      { status: 500 }
    )
  }
}

数据获取

在服务器组件中进行数据获取(默认情况下,page.tsx 是服务器组件):

tsx 复制代码
// app/blog/page.tsx - 服务器组件
import Link from 'next/link';
import BlogActions from './components/BlogActions';

// 模拟博客数据
const blogs = [
  { 
    id: '1', 
    title: 'Next.js入门指南',
    excerpt: '了解如何使用Next.js构建现代Web应用',
    author: {
      name: '张三',
      avatar: 'https://randomuser.me/api/portraits/men/1.jpg'
    },
    publishedAt: '2023-05-15',
    tags: ['Next.js', 'React', '前端开发']
  },
  { 
    id: '2', 
    title: 'React服务器组件详解',
    excerpt: '深入理解React服务器组件的工作原理',
    author: {
      name: '李四',
      avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
    },
    publishedAt: '2023-06-22',
    tags: ['React', '服务器组件', '性能优化']
  },
  { 
    id: '3', 
    title: 'TypeScript与Next.js',
    excerpt: '如何在Next.js项目中充分利用TypeScript',
    author: {
      name: '王五',
      avatar: 'https://randomuser.me/api/portraits/men/3.jpg'
    },
    publishedAt: '2023-07-10',
    tags: ['TypeScript', 'Next.js', '类型安全']
  }
];

// 模拟获取博客列表函数
async function getBlogs() {
  // 模拟网络延迟
  await new Promise(resolve => setTimeout(resolve, 500));
  return blogs;
}

export default async function BlogsPage() {
  // 获取博客数据
  const blogList = await getBlogs();
  
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="flex justify-between items-center mb-8">
        <h1 className="text-3xl font-bold">博客列表</h1>
        <Link 
          href="/blog/new" 
          className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition"
        >
          创建新博客
        </Link>
      </div>
      
      <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
        {blogList.map(blog => (
          <div key={blog.id} className="border rounded-lg overflow-hidden hover:shadow-md transition">
            <div className="p-6">
              <h2 className="text-xl font-bold mb-3">{blog.title}</h2>
              <p className="text-gray-600 mb-4">{blog.excerpt}</p>
              
              <div className="flex flex-wrap gap-2 mb-4">
                {blog.tags.map(tag => (
                  <span 
                    key={tag} 
                    className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded"
                  >
                    {tag}
                  </span>
                ))}
              </div>
              
              <div className="flex items-center text-sm text-gray-500 mb-4">
                <img 
                  src={blog.author.avatar} 
                  alt={blog.author.name}
                  className="w-6 h-6 rounded-full mr-2"
                />
                <span>{blog.author.name}</span>
                <span className="mx-2">•</span>
                <span>{new Date(blog.publishedAt).toLocaleDateString('zh-CN')}</span>
              </div>
              
              <div className="flex space-x-2">
                <Link 
                  href={`/blog/${blog.id}`} 
                  className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 text-sm"
                >
                  查看全文
                </Link>
                <Link 
                  href={`/blog/edit/${blog.id}`} 
                  className="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600 text-sm"
                >
                  编辑
                </Link>
                <BlogActions blogId={blog.id} />
              </div>
            </div>
          </div>
        ))}
      </div>
      
      {blogList.length === 0 && (
        <div className="text-center py-12">
          <p className="text-gray-500 mb-4">暂无博客内容</p>
          <Link 
            href="/blog/new" 
            className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
          >
            创建第一篇博客
          </Link>
        </div>
      )}
      
      <div className="mt-8 text-center">
        <Link 
          href="/" 
          className="text-blue-600 hover:underline"
        >
          返回首页
        </Link>
      </div>
    </div>
  );
} 

使用客户端组件进行交互:

tsx 复制代码
// blog/components/BlogActions.tsx
'use client';

interface BlogActionsProps {
  blogId: string;
}

export default function BlogActions({ blogId }: BlogActionsProps) {
  const handleDelete = () => {
    alert(`删除功能尚未实现:${blogId}`);
    // 这里可以实现实际的删除逻辑
  };

  return (
    <button 
      className="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 text-sm"
      onClick={handleDelete}
    >
      删除
    </button>
  );
} 

安装依赖

使用 pnpm 安装项目依赖:

bash 复制代码
# 安装依赖
pnpm add axios swr

# 安装开发依赖
pnpm add -D typescript @types/react eslint

运行开发服务器

bash 复制代码
pnpm dev

构建和部署

bash 复制代码
# 构建应用
pnpm build

# 启动生产环境服务器
pnpm start

pnpm 优势

pnpm相比npm和yarn有以下优势:

  1. 磁盘空间效率:pnpm使用硬链接和内容寻址存储,减少了重复的依赖
  2. 安装速度快:比npm和yarn快2-3倍
  3. 更严格的依赖管理:通过使用符号链接确保依赖访问更安全
  4. 内置monorepo支持:无需额外工具即可管理多包项目

pnpm 常用命令

bash 复制代码
# 初始化项目
pnpm init

# 安装所有依赖
pnpm install

# 添加依赖
pnpm add [package]

# 添加开发依赖
pnpm add -D [package]

# 更新依赖
pnpm update

# 运行脚本
pnpm [script]

# 删除依赖
pnpm remove [package]

Node.js 与 Next.js 的关系

Node.js 与 Next.js 的基本关系

Next.js 是构建在 Node.js 之上的 React 框架。这种关系可以从多个方面理解:

  1. 运行时环境:Next.js 使用 Node.js 作为其服务器端运行时环境
  2. 构建工具:Next.js 利用 Node.js 生态系统中的工具(如 webpack、babel)进行代码构建和转换
  3. 包管理:Next.js 项目通过 npm、yarn 或 pnpm 等 Node.js 包管理器管理依赖
  4. API 实现:Next.js 的服务器端 API 路由基于 Node.js 的 HTTP 模块实现

Next.js 的运行时环境

Next.js 确实在 Node.js 环境中启动了一个服务器来接收来自浏览器的请求。这个过程在不同模式下有所不同:

开发环境

(pnpm dev)

在开发模式下:

  1. Next.js 启动一个 Node.js HTTP 服务器(默认监听 3000 端口)

  2. 该服务器具有热模块替换(HMR)功能,允许实时更新

  3. 当浏览器请求到达时,Next.js 服务器根据请求的路径:

    • 对于页面请求:执行服务器端渲染(SSR)或提供静态生成(SSG)的内容
    • 对于 API 请求:执行相应的 API 路由处理函数
    • 对于静态资源:提供 public 目录中的文件
  4. 开发服务器还处理源代码编译、打包和监视文件变化

    浏览器请求 → Node.js服务器(Next.js) → 路由解析 → 页面渲染/API处理 → 响应返回

生产环境

(pnpm build 然后 pnpm start)

在生产模式下:

  1. pnpm build 预先构建所有可能的页面和资源

    • 静态生成(SSG)的页面被预渲染为HTML
    • 服务器组件被优化和序列化
    • JavaScript包被优化和代码分割
  2. pnpm start 启动一个优化的 Node.js 生产服务器

    • 这个服务器比开发服务器轻量得多
    • 它主要负责:
      • 提供预构建的静态资源
      • 处理动态SSR请求
      • 执行API路由

    浏览器请求 → Node.js生产服务器 → 提供预构建资源/动态渲染 → 响应返回

渲染模式与Node.js的关系

  1. 服务器端渲染(SSR)

    • 每次请求都在 Node.js 环境中执行React组件渲染
    • 生成HTML并发送给浏览器
    • 适用于需要最新数据的页面
  2. 静态站点生成(SSG)

    • 在构建时在 Node.js 环境中预渲染HTML
    • 请求来临时直接提供静态HTML
    • 适用于内容不经常变化的页面
  3. 增量静态再生成(ISR)

    • 结合SSG和SSR的优点
    • 预渲染HTML,但在指定间隔后在Node.js环境中重新生成
  4. 客户端渲染

    • 初始HTML由服务器提供
    • 后续渲染和数据获取在浏览器中发生
    • 减轻Node.js服务器负载

Node.js 环境的限制

在使用Next.js时,需要注意Node.js环境的一些特点和限制:

  1. 服务器组件 vs 客户端组件

    • 服务器组件在Node.js环境中运行,可以访问文件系统、环境变量等
    • 客户端组件无法访问Node.js特有的功能和API
  2. API路由的Node.js能力

    • API路由在Node.js环境中执行,可以使用完整的Node.js功能
    • 包括数据库连接、文件系统操作、复杂计算等
  3. 边缘运行时

    • Next.js还支持Edge Runtime(一种轻量级运行时)
    • Edge Runtime比Node.js更受限,但部署和冷启动更快

部署架构

Next.js应用的部署涉及到Node.js服务器的管理:

  1. 传统服务器

    • 部署完整的Node.js服务器
    • 例如在AWS EC2、DigitalOcean等上运行
  2. 无服务器函数

    • 将Next.js应用部署为无服务器函数
    • 例如AWS Lambda、Vercel等
  3. 静态导出

    • 完全静态导出,不需要Node.js服务器
    • 使用 next export 命令
    • 适用于不需要SSR或API路由的项目

本目录示例代码说明

本目录包含以下示例文件:

  1. page.tsx: 一个简单的 Next.js 首页示例,展示了:

    • 页面组件结构
    • 使用 next/head 管理头部元素
    • 使用 next/link 进行客户端导航
    • React hooks 在 Next.js 中的使用
  2. [id].tsx: 展示动态路由的实现,包括:

    • 动态路由参数获取
    • 静态生成 (generateStaticParams)
    • 数据获取模式
  3. route.ts: API 路由示例,展示了:

    • 基于请求方法的处理逻辑
    • 响应处理
    • 错误处理

注意:这些示例基于 App Router 模式实现。

App Router 和 Pages Router 的区别

特性 App Router (app/) Pages Router (pages/)
组件模型 React Server Components 客户端组件
数据获取 组件中的 fetch 函数 getServerSideProps/getStaticProps
布局 layout.tsx _app.tsx 和布局组件
嵌套布局 多个 layout.tsx 需手动实现
加载状态 loading.tsx 需手动实现
错误处理 error.tsx 需手动实现或使用 Error Boundaries
API 路由 route.ts 处理程序 pages/api/*.ts

进阶资源

练习建议

  1. 创建一个包含多个页面的 Next.js 应用(使用 App Router)
  2. 实现动态路由和数据获取
  3. 添加多级嵌套布局
  4. 创建 API 路由
  5. 实现错误处理和加载状态
  6. 将项目部署到 Vercel 或其他托管平台

容器知识入门教程

容器技术是现代应用开发和部署的基石,本教程将介绍 Docker 容器的基础知识。

Docker 背景介绍

什么是 Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 或 Windows 操作系统的机器上。Docker 使用了 Linux 内核的多种功能(如 Namespaces、Cgroups)来创建独立的容器。

Docker 的发展历史

  • 2013年:Docker 由 dotCloud 公司(后更名为 Docker Inc.)推出,最初是 dotCloud 平台的内部项目
  • 2014年:Docker 1.0 发布,正式进入生产环境
  • 2015年:Docker Compose、Docker Swarm 和 Docker Machine 等工具发布,生态系统开始繁荣
  • 2016年:引入内置的编排功能
  • 2017年:集成 Kubernetes 支持
  • 至今:持续迭代发展,成为容器化技术的事实标准

为什么需要 Docker

在 Docker 出现之前,开发者面临以下问题:

  1. 环境不一致:开发、测试、生产环境的差异导致"在我电脑上能运行"的问题
  2. 部署复杂:应用依赖安装复杂,配置繁琐
  3. 资源利用率低:传统虚拟化方案资源占用高,启动慢
  4. 应用隔离困难:不同应用之间相互影响
  5. 扩展性差:难以快速扩容和缩容

Docker 通过容器化技术解决了这些问题:

  1. 一致的环境:无论在哪里运行,容器内的环境都是一样的
  2. 轻量级:容器共享主机系统内核,比传统虚拟机占用资源少,启动更快
  3. 隔离:容器之间彼此隔离,不会相互影响
  4. 可移植性:构建一次,到处运行
  5. 微服务支持:适合现代微服务架构,每个服务独立容器化

Docker vs 虚拟机

特性 Docker 容器 虚拟机
启动时间 秒级 分钟级
存储空间 MB级 GB级
性能 接近原生 有所损耗
系统资源 共享宿主机内核 独立内核
隔离性 进程级隔离 完全隔离
运行密度 单机可运行数十至数百个容器 单机通常运行数个虚拟机

1. Docker 安装

Windows 安装

  1. 下载 Docker Desktop for Windows
  2. 双击安装程序并按照提示完成安装
  3. 安装完成后,Docker Desktop 会自动启动
  4. 在系统托盘中可以看到 Docker 图标,表示 Docker 服务正在运行

macOS 安装

  1. 下载 Docker Desktop for Mac
  2. 将下载的 .dmg 文件拖到应用程序文件夹
  3. 启动 Docker Desktop 应用
  4. 等待 Docker 初始化完成,顶部状态栏会显示 Docker 图标

Linux 安装 (Ubuntu)

bash 复制代码
# 更新软件包索引
sudo apt-get update

# 安装依赖
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 设置稳定版仓库
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker Engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# 将当前用户添加到 docker 组(避免每次都使用 sudo)
sudo usermod -aG docker $USER
# 需要重新登录使配置生效

验证安装

bash 复制代码
# 查看 Docker 版本
docker --version

# 运行测试容器
docker run hello-world

2. 常用 Docker 命令

镜像相关命令

bash 复制代码
# 搜索镜像
docker search ubuntu

# 拉取镜像
docker pull ubuntu:latest

# 列出本地镜像
docker images

# 删除镜像
docker rmi ubuntu:latest

# 构建镜像
docker build -t myapp:1.0 .

容器相关命令

bash 复制代码
# 创建并启动容器
docker run -d -p 8080:80 --name mywebserver nginx

# 列出所有运行中的容器
docker ps

# 列出所有容器(包括已停止的)
docker ps -a

# 停止容器
docker stop mywebserver

# 启动已停止的容器
docker start mywebserver

# 重启容器
docker restart mywebserver

# 删除容器
docker rm mywebserver

# 进入容器交互式终端
docker exec -it mywebserver bash

# 查看容器日志
docker logs mywebserver

# 查看容器资源使用情况
docker stats mywebserver

Docker Compose 命令

bash 复制代码
# 启动所有服务
docker-compose up -d

# 停止所有服务
docker-compose down

# 查看服务状态
docker-compose ps

# 查看服务日志
docker-compose logs

# 重建服务
docker-compose build

网络和存储命令

bash 复制代码
# 创建网络
docker network create mynetwork

# 列出网络
docker network ls

# 创建卷
docker volume create mydata

# 列出卷
docker volume ls

示例项目说明

本目录包含一个简单的 Docker 示例项目,包括:

  1. Dockerfile: 定义如何构建应用容器镜像
  2. docker-compose.yml: 定义多容器应用的服务、网络和卷
  3. app.js: 一个简单的 Node.js Express 应用
  4. package.json: Node.js 应用依赖定义

如何运行示例项目

  1. 确保已安装 Docker 和 Docker Compose

  2. 在此目录下运行:

    bash 复制代码
    docker-compose up -d
  3. 访问应用:

项目文件说明

Dockerfile

这个文件定义了如何构建应用容器:

  • 使用 Node.js 16 Alpine 作为基础镜像
  • 设置工作目录
  • 复制和安装依赖
  • 配置环境变量
  • 指定启动命令

docker-compose.yml

这个文件定义了完整的应用栈:

  • Web 应用服务 (使用 Dockerfile 构建)
  • PostgreSQL 数据库服务
  • Redis 缓存服务
  • 网络配置
  • 卷配置(持久存储)

app.js

一个简单的 Express 服务器,展示容器环境信息和健康检查端点。

Docker 网络详解

Docker 网络是容器化环境中的关键组件,提供了容器间的通信基础设施。

Docker 网络的主要作用

  1. 容器间通信:允许不同容器在不暴露端口到主机的情况下相互通信
  2. 隔离环境:可以创建完全隔离的网络环境,提高应用安全性
  3. 服务发现:容器可以通过容器名称而非IP地址相互访问,简化服务发现
  4. 多主机连接:使用overlay网络可以连接不同主机上的容器
  5. 网络策略控制:可以精细控制哪些容器可以相互通信

常用网络类型

bash 复制代码
# 查看可用的网络驱动
docker info | grep "Network"

# 创建自定义网络
docker network create --driver bridge my-network

# 在创建容器时连接到指定网络
docker run --network=my-network -d --name container1 nginx

# 将已有容器连接到网络
docker network connect my-network container2

网络驱动类型

  • bridge: 默认网络驱动,适用于同一主机上的容器
  • host: 直接使用主机网络,移除容器与主机间的网络隔离
  • overlay: 用于Docker Swarm环境中,连接多个Docker守护进程
  • macvlan: 允许容器拥有独立的MAC地址,直接连接到物理网络
  • none: 禁用所有网络

Docker 卷详解

Docker卷提供了容器数据的持久化存储解决方案,解决了容器销毁后数据丢失的问题。

Docker 卷的主要作用

  1. 数据持久化:即使容器被删除,存储在卷中的数据依然保留
  2. 数据共享:多个容器可以挂载相同的卷,实现数据共享
  3. 备份与恢复:简化数据备份和恢复流程
  4. 性能优化:与容器内部存储相比,卷通常提供更好的I/O性能
  5. 存储解耦:将应用与数据分离,提高系统灵活性和可维护性

卷的使用方式

bash 复制代码
# 创建卷
docker volume create my-data

# 查看卷的详细信息
docker volume inspect my-data

# 在容器中使用卷
docker run -d --name my-container -v my-data:/app/data nginx

# 使用绑定挂载(挂载主机目录)
docker run -d --name my-container -v $(pwd):/app/data nginx

# 备份卷中的数据
docker run --rm -v my-data:/source -v $(pwd):/backup alpine tar -czvf /backup/my-data-backup.tar.gz -C /source .

卷的类型

  • 命名卷: 由Docker管理的命名存储空间
  • 绑定挂载: 直接映射主机文件系统的路径到容器
  • tmpfs挂载: 将数据存储在主机的内存中,不写入文件系统

使用卷时要考虑权限、备份策略和数据生命周期管理,以确保数据安全和可靠性。

Docker 进阶概念

  1. Docker 多阶段构建:优化镜像大小和构建过程
  2. Docker 网络:bridge、host、overlay 等不同网络驱动
  3. Docker 卷:持久化数据存储
  4. Docker Swarm:Docker 原生集群和编排工具
  5. Docker 安全:最佳实践和安全配置
  6. Docker Registry:镜像仓库和分发

相关资源

练习建议

  1. 尝试为不同语言的应用创建 Dockerfile
  2. 练习使用 Docker Compose 设置多容器应用
  3. 探索 Docker 卷和网络
  4. 学习如何在生产环境中安全地部署 Docker 容器

全栈博客案例

代码仓库

go-learning:https://github.com/BaiZe1998/go-learning/tree/main/doutok-course/basic-knowledge

相关推荐
豆沙沙包?16 分钟前
6.学习笔记-SpringMVC-拦截器(P71-P74)
笔记·学习
Fency咖啡17 分钟前
《代码整洁之道》第4章 注释 - 笔记
笔记
Dovis(誓平步青云)20 分钟前
【数据结构】·励志大厂版(复习+刷题):二叉树
c语言·数据结构·经验分享·笔记·学习·算法·学习方法
豆沙沙包?5 小时前
5.学习笔记-SpringMVC(P61-P70)
数据库·笔记·学习
丶Darling.8 小时前
26考研 | 王道 | 数据结构笔记博客总结
数据结构·笔记·考研
道长没有道观8 小时前
计算机操作系统笔记
笔记·考研·操作系统
一点.点10 小时前
李沐动手深度学习(pycharm中运行笔记)——04.数据操作
pytorch·笔记·python·深度学习·pycharm·动手深度学习
我的golang之路果然有问题13 小时前
案例速成GO+redis 个人笔记
经验分享·redis·笔记·后端·学习·golang·go
韩明君13 小时前
前端学习笔记(四)自定义组件控制自己的css
前端·笔记·学习