从零开始的 DevOps(手动流程)
Web 应用程序
graph LR
A[开始] --> B{出错?};
B -->|是| C[嗯...];
C --> D[调试];
D --> B;
B ---->|否| E[耶!];设置与依赖
使用 Pyenv 和 Poetry 管理 Python 依赖
首先,让我们在您的系统上安装 Pyenv。然后,让我们选择一个较新的 Python 版本,以便为我们的“从零开始的 DevOps(手动流程)”设置一个由 Poetry 管理的虚拟环境。
#!/bin/bash
set -x #echo on
PYTHON_VERSION=3.11.1
echo "正在设置 Python v$PYTHON_VERSION"
echo $PYTHON_VERSION > .python-version
pyenv install $PYTHON_VERSION
pyenv global $PYTHON_VERSION
pyenv local $PYTHON_VERSION
pyenv shell $PYTHON_VERSION
echo "Poetry 安装与虚拟环境创建"
pyenv exec pip install poetry
pyenv exec poetry init
pyenv exec poetry install
pyenv exec poetry shell
echo "将 Python 依赖安装到虚拟环境中"
pyenv exec poetry add black --group dev # 添加开发依赖
echo "虚拟环境可视化检查"
pyenv exec poetry show -v
pyenv exec poetry env info -p#!/bin/bash
set -x #echo on
pyenv exec poetry run python $@[tool.poetry]
name = "devops-from-scratch-manual-process"
version = "0.1.0"
description = "DevOps from Scratch (Manual Setup)"
authors = ["user "]
license = "MIT"
readme = "README.md"
#packages = [{include = "devops_from_scratch_manual_process"}]
[tool.poetry.dependencies]
python = "^3.10.6"
#python = "^3.11"
Django = "^4.2"
django-debug-toolbar = "^4.0"
sortedcontainers = "^2.4.0"
httpx = "^0.23.0"
whitenoise = "^6.2.0"
fontawesomefree = "^6.4.0"
typer = { version = "^0.9.0", extras = ["all"] }
markdown = "^3.4.3"
#[tool.poetry.group.dev.dependencies]
#black = "^23.3.0"
#pytest = "7.3.1"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"应用程序命令行界面 (CLI)
CLI 将帮助我们触发 Web 应用程序的管理任务。
import typer
app = typer.Typer()
@app.command()
def hello(name: str):
print(f"Hello {name}")
@app.command()
def goodbye(name: str, formal: bool = False):
if formal:
print(f"Goodbye Mr/Ms {name}. Have a good day.")
else:
print(f"Bye {name}!")Web 应用程序
Markdown 解析器
from typing import List
from pathlib import Path
from markdown import markdown
def parseMarkdownPosts(path: str) -> List[str]:
p = Path(path)
mdFilePaths = list(p.glob('**/*.md'))
postsHtml = [_parseMarkdown(filePath) for filePath in mdFilePaths]
return postsHtml
def _parseMarkdown(path: str) -> str:
data = Path(path).read_text()
html = markdown(data)
return html---
title: My First Post
---
# 我的第一篇文章
欢迎来到我的博客!这是我的第一篇文章。
## 一些 Markdown 特性
- * 粗体: **粗体文本**
- * 斜体: *斜体文本*
- * 删除线: ~~删除线文本~~
- * [链接](https://example.com)---
title: My Second Post
---
# 我的第二篇文章
这是我的第二篇文章,位于嵌套目录中。从 CLI 处理 Markdown 文件
@app.command()
def markdown(mrkdwndir: str):
import sys
from pathlib import Path
current_dir = Path(__file__).parent.resolve()
sys.path.insert(1, current_dir)
from services.postsvc import parseMarkdownPosts
print(f"正在递归解析目录中的 Markdown 文件: {mrkdwndir}")
postsHtml = parseMarkdownPosts(mrkdwndir)
for html in postsHtml:
print(html)
if __name__ == "__main__":
app()Django 框架
让我们实现一个由数据库支持的简单 TODO 列表应用程序。
#!/bin/bash
set -x #echo on
pyenv exec poetry run django-admin startproject $@./scripts/local/new-django.sh mytodos更多
让我们忽略不需要的文件:
# Project
__pycache__
.idea
*.sqlite3
*.pem
*.log
perf-report.html
MyTODOs 项目
# 空!!!!ASGI
"""
mytodos 项目的 ASGI 配置。
它将 ASGI 可调用对象公开为名为 ``application`` 的模块级变量。
有关此文件的更多信息,请参阅
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mytodos.settings")
application = get_asgi_application()WSGI
"""
mytodos 项目的 WSGI 配置。
它将 WSGI 可调用对象公开为名为 ``application`` 的模块级变量。
有关此文件的更多信息,请参阅
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mytodos.settings")
application = get_wsgi_application()设置 (SETTINGS)
"""
mytodos 项目的 Django 设置。
由 'django-admin startproject' 使用 Django 4.2 生成。
有关此文件的更多信息,请参阅
https://docs.djangoproject.com/en/4.2/topics/settings/
有关设置及其值的完整列表,请参阅
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
# 在项目内部构建路径,例如:BASE_DIR / 'subdir'。
BASE_DIR = Path(__file__).resolve().parent.parent
# 快速开发设置 - 不适合生产环境
# 请参阅 https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# 安全警告:保持生产环境中使用的密钥机密!
SECRET_KEY = "django-insecure-r3#=zp=^#5ehd-*ulh0v&x+b3y$lycz=4-=+=_2nn#cipqi8rl"
# 安全警告:不要在生产环境中开启调试模式!
DEBUG = True
ALLOWED_HOSTS = []
# 应用程序定义
INSTALLED_APPS = [
"fontawesomefree", # 免费字体
"crud.apps.CrudConfig", # TODO 的 CRUD
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "mytodos.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "mytodos.wsgi.application"
# 数据库
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# 密码验证
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# 国际化
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# 静态文件 (CSS, JavaScript, 图片)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
# 默认主键字段类型
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"None
URL 配置
"""
mytodos 项目的 URL 配置。
`urlpatterns` 列表将 URL 路由到视图。有关更多信息,请参阅:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
示例:
函数视图
1. 添加导入: from my_app import views
2. 添加 URL 到 urlpatterns: path('', views.home, name='home')
基于类的视图
1. 添加导入: from other_app.views import Home
2. 添加 URL 到 urlpatterns: path('', Home.as_view(), name='home')
包含另一个 URLconf
1. 导入 include() 函数: from django.urls import include, path
2. 添加 URL 到 urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("", include("crud.urls", namespace="crud")),
path("admin/", admin.site.urls),
]从 CLI 管理 Django 项目
#!/usr/bin/env python
"""Django 用于管理任务的命令行工具。"""
import os
import sys
def main():
"""运行管理任务。"""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mytodos.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"无法导入 Django。您确定它已安装并可在您的 PYTHONPATH 环境变量中找到吗?"
"您是否忘记激活虚拟环境了?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()新建 Django 应用
#!/bin/bash
set -x #echo on
pyenv exec poetry run `pwd`/manage.py startapp $@新建一个名为 CRUD 的应用,用于执行 CRUD 操作以帮助跟踪我们的 TODO:
./scripts/local/new-django-app.sh crud建模 TODO
from django.db import models
# 在此处创建您的模型
class Todo(models.Model):
name = models.CharField(max_length=100)
complete = models.BooleanField(default=False)
#created_at = models.DateTimeField('Created', auto_now_add=True)
#updated_at = models.DateTimeField('Updated', auto_now=True)
def __str__(self):
return self.nameTODO 端点
from django.shortcuts import render, get_object_or_404, redirect
from django.views import generic
from django.http import HttpResponseRedirect
# 在此处创建您的视图。
from .models import Todo
class IndexView(generic.ListView):
template_name = 'crud/index.html'
context_object_name = 'todo_list'
def get_queryset(self):
"""返回所有最新的 crud。"""
return Todo.objects.order_by('-name')
#def get_queryset(self):
# """返回所有最新的 crud。"""
# return Todo.objects.order_by('-created_at')
def add(request):
name = request.POST['name']
Todo.objects.create(name=name)
return redirect('crud:index')
def delete(request, todo_id):
todo = get_object_or_404(Todo, pk=todo_id)
todo.delete()
return redirect('crud:index')
def update(request, todo_id):
todo = get_object_or_404(Todo, pk=todo_id)
complete = request.POST.get('complete', False)
if complete == 'on':
complete = True
todo.complete = complete
todo.save()
return redirect('crud:index')TODO 模板
{% load static %}
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>我的 TODOstitle>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<link href="{% static 'fontawesomefree/css/fontawesome.css' %}" rel="stylesheet" type="text/css">
<link href="{% static 'fontawesomefree/css/brands.css' %}" rel="stylesheet" type="text/css">
<link href="{% static 'fontawesomefree/css/solid.css' %}" rel="stylesheet" type="text/css">
<script src="https://unpkg.com/htmx.org@1.9.2">script>
head>
<body>
{% block content %}
<h1>你好,世界!h1>
{% endblock %}
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous">script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous">script>
body>
html>{% extends 'crud/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="offset-md-2 col-lg-9">
<div class="page-header">
<h1>
Todo 列表
h1>
div>
div>
div>
<div class="row">
<div class="offset-md-2 col-lg-9">
<form method="post" action="{% url 'crud:add' %}">
{% csrf_token %}
<div class="form-row">
<div class="col-md-6">
<input type="text" class="form-control" name="name" placeholder="洗衣服" required>
div>
<div class="col-md-6">
<button type="submit" name="submit" class="btn btn-outline-primary">
添加
button>
div>
div>
form>
div>
div>
<hr />
<div class="row">
<div class="offset-md-2 col-lg-6">
<div class="list-group">
{% for todo in todo_list %}
<div class="list-group-item {% if todo.complete %} todo-complete {% endif %}">
<form style="display: inline;" method="post" action="{% url 'crud:update' todo.id %}">
{% csrf_token %}
<input type="checkbox" name="complete" onchange="this.form.submit()" {% if todo.complete %} checked
{% endif %} class="todo-status-checkbox"
title="{% if not todo.complete %} 标记为完成 {% else %} 标记为未完成 {% endif %}">
form>
{{ todo.name }}
<a href="{% url 'crud:delete' todo.id %}" title="删除">
<i class="far fa-trash-alt">i>
a>
div>
{% endfor %}
div>
div>
div>
div>
{% endblock %}URL 配置
CRUD Urls
from django.urls import path
from . import views
app_name='todos'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('/delete', views.delete, name='delete'),
path('/update', views.update, name='update'),
path('add/', views.add, name='add')
]迁移数据库
./scripts/local/pyrun.sh ./manage.py migrate为 MyTODOs CRUD 生成迁移文件
./scripts/local/pyrun.sh ./manage.py makemigrations crud为 MyTODOs CRUD 创建表
./scripts/local/pyrun.sh ./manage.py migrateLightsail 部署
让我们在 AWS 上配置一台经济实惠的虚拟机:
- 导航至 AWS Lightsail 以创建虚拟机
- 让我们选择一台运行较新版本 Ubuntu – Jammy Jellyfish (22.04 LTS) 的虚拟机
- 使用 SSH 和 PEM 密钥连接到虚拟机
- 以非常原始且危险的方式设置和配置虚拟机
- 将应用程序文件传输到虚拟机
- 确保项目持续运行 (nohup vs supervisor)
下载用于安全 SSH 和 SCP 连接到虚拟机的 PEM 密钥
chmod 400 mytodos-on-ubuntu-key.pem#!/bin/bash
set -x #echo on
ssh -i `pwd`/$1.pem $2@$3#!/bin/bash
set -x #echo on
# 我是谁?
whoami
# 检查 Python
which python3 # python3 在较新版本的 Ubuntu 上是预装的
which pip3 # 检查是否安装了 python3-pip
which poetry # 检查是否安装了 python3-poetry
# 更新 Ubuntu 软件包注册表列表
sudo apt update
# 安装 Poetry
sudo apt install python3-pip python3-poetry#!/bin/bash
set -x #echo on
scp -i `pwd`/$1.pem -r $2 $3@$4:$5 # -r 用于递归复制文件[inet_http_server]
port = 0.0.0.0:9001
username = user
password = 1234
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisord]
serverurl=http://0.0.0.0:9001
[program:mytodos]
directory = /home/ubuntu/mytodos_app
command = sudo poetry run python manage.py runserver 0.0.0.0:80
autostart = true
autorestart = true
#stderr_logfile = /var/log/mytodos/app.err.log
#stdout_logfile = /var/log/mytodos/app.out.log性能测试
import http from 'k6/http';
import { sleep, check } from 'k6';
import { htmlReport } from 'https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js';
import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js';
export let options = {
// vus: 100,
// duration: '30s',
// iterations: 10,
// minIterationDuration: '10s',
stages: [
{ duration: '25s', target: 32 }, // 4 PODS
{ duration: '1m', target: 80 }, // 4 PODS
// { duration: '300s', target: 800 },
// { duration: '600s', target: 1200 },
// { duration: '14m40s', target: 4000 },
// { duration: '4m40s', target: 1600 },
// { duration: '8m40s', target: 8000 },
// { duration: '14m40s', target: 18000 }, Perf Box dies that High
{ duration: '15s', target: 0 },
],
// batch: 8000,
// batch: 4000,
batch: 100,
// batch: 1200,
// batchPerHost: 18000000,
batchPerHost: 1440000,
// batchPerHost: 640000000,
noConnectionReuse: false,
// noConnectionReuse: true,
discardResponseBodies: true,
};
let requestHeaders = {
'User-Agent': 'k6',
'Accept': 'application/json',
// 'Content-Type': 'application/json',
// 'Authorization': 'Bearer {{ .Jwt }}',
'X-Consumer-Username': 'k6-Benchmarker',
};
export default function () {
const res = http.get(
'http://3.96.193.218',
{headers: requestHeaders}
);
// sleep(1);
const checkRes = check(res, {
'status is 200': (r) => r.status === 200,
// 'response body': (r) => r.body.indexOf('Feel free to browse') !== -1,
});
}
export function handleSummary(data) {
return {
'./perf-report.html': htmlReport(data),
stdout: textSummary(data, { indent: ' ', enableColors: true }),
};
}英语
幻灯片
Webapp:
工具:
我们将使用 Django Web 框架来创建一个简单的 TODO 应用程序。Django 是一个高级 Python Web 框架,能够实现快速开发和简洁、务实的设计。您可以访问官方网站了解更多关于 Django 的信息:https://www.djangoproject.com/
演讲者笔记:
我们的演讲者将介绍我们将要构建和部署的 Web 应用程序,解释其目的以及与 DevOps 工作流程的相关性。
构建与测试:
工具:
为了构建和测试我们的 Web 应用程序,我们将使用 Python Poetry 和 Pytest。Poetry 是一个 Python 依赖管理工具,简化了包管理过程。Pytest 是一个流行的测试框架,可以轻松编写和运行单元测试。您可以访问官方网站了解更多关于 Python Poetry 的信息:https://python-poetry.org/,以及在这里了解更多关于 Pytest 的信息:https://pytest.org/
演讲者笔记:
我们将逐步介绍构建和测试应用程序的过程,强调测试的重要性以及它如何融入 DevOps 工作流程。
虚拟机配置:
工具:
我们将使用 AWS Lightsail 和 Bash 来配置我们的虚拟机。AWS Lightsail 是一个简化的云平台,可以轻松启动和管理虚拟专用服务器、存储和网络。Bash 是一种 Unix shell 和命令语言,广泛用于 DevOps 工作流程。您可以在此处了解更多关于 AWS Lightsail 的信息:https://aws.amazon.com/lightsail/,以及在此处了解关于 Bash 的信息:https://www.gnu.org/software/bash/
演讲者笔记:
我们的演讲者将讨论为托管应用程序配置虚拟机的过程,解释可用的不同选项以及如何为您的需求选择最佳选项。
数据库配置:
工具:
对于我们的数据库配置,我们将使用 AWS Lightsail PostgreSQL 或 CockroachDB 作为替代方案。PostgreSQL 是一个功能强大的开源关系数据库管理系统,广泛用于 Web 应用程序开发。CockroachDB 是一个专为可扩展性和弹性而设计的分布式 SQL 数据库。您可以在此处了解更多关于 AWS Lightsail PostgreSQL 的信息:https://aws.amazon.com/lightsail/features/databases/,以及在此处了解关于 CockroachDB 的信息:https://www.cockroachlabs.com/
演讲者笔记:
我们将讨论为应用程序配置数据库的过程,并探索可用的不同选项。
部署:
工具:
为了将我们的应用程序部署到虚拟机,我们将使用 SSH 和 SCP。SSH (Secure Shell) 是一种安全网络协议,允许两个系统之间进行加密通信。SCP (Secure Copy) 是一个用于在两个系统之间安全传输文件的命令行工具。您可以在此处了解更多关于 SSH 的信息:https://www.ssh.com/ssh/,以及在此处了解关于 SCP 的信息:https://linuxize.com/post/how-to-use-scp-command-to-securely-transfer-files/
演讲者笔记:
我们的演讲者将引导我们完成将应用程序部署到虚拟机的过程,并解释自动化在部署中的重要性。
负载均衡器:
工具:
为了确保我们应用程序的可靠性和可扩展性,我们将使用 NGINX 作为我们的负载均衡器。NGINX 是一个流行的开源 Web 服务器和反向代理,以其高性能和可扩展性而闻名。您可以在此处了解更多关于 NGINX 的信息:https://www.nginx.com/
演讲者笔记:
我们将讨论负载均衡对 Web 应用程序的重要性,并逐步介绍为应用程序设置负载均衡器的过程。
自定义域名:
工具:
我们将使用 AWS Lightsail 为我们的应用程序设置自定义域名。自定义域名为您的 Web 应用程序提供了更专业和品牌化的 URL,并可以改善用户体验。您可以在此处了解更多关于使用 AWS Lightsail 设置自定义域名的信息:https://aws.amazon.com/lightsail/features/dns/
演讲者笔记:
我们的演讲者将引导我们完成为应用程序设置自定义域名的过程,解释品牌和用户体验的重要性。
崩溃恢复能力:
工具:
我们将使用 Supervisord 来确保我们应用程序的崩溃恢复能力。Supervisord 是一个客户端/服务器系统,允许在类 Unix 操作系统上控制和监控进程。您可以在此处了解更多关于 Supervisord 的信息:http://supervisord.org/
演讲者笔记:
我们将讨论 Web 应用程序崩溃恢复能力的重要性,并探索如何使用 DevOps 实践来实现它。
日志记录与监控:
工具:
对于我们的日志记录和监控需求,我们将使用 Django Logging 和 Supervisord UI。Django Logging 是 Django Web 框架的内置日志系统,为记录应用程序中的事件提供了一种灵活且可配置的方式。Supervisord UI 是一个基于 Web 的界面,用于管理和监控由 Supervisord 控制的进程。您可以在此处了解更多关于 Django Logging 的信息:https://docs.djangoproject.com/en/3.2/topics/logging/,以及在此处了解关于 Supervisord UI 的信息:https://github.com/Supervisor/supervisor/blob/master/docs/webui.rst
演讲者笔记:
我们的演讲者将讨论 Web 应用程序日志记录和监控的重要性,并逐步介绍为应用程序设置日志记录和监控的过程。
新需求带来的更新:
工具:
我们将使用 SCP 和 Django 迁移来根据新需求更新我们的应用程序。SCP (Secure Copy) 是一个用于在两个系统之间安全传输文件的命令行工具,而 Django 迁移提供了一种随着应用程序发展更新数据库架构的方法。您可以在此处了解更多关于 Django 迁移的信息:https://docs.djangoproject.com/en/3.2/topics/migrations/,以及在此处了解关于 SCP 的信息:https://linuxize.com/post/how-to-use-scp-command-to-securely-transfer-files/
演讲者笔记:
我们将讨论根据新需求更新应用程序的过程,并解释 DevOps 实践如何使此过程更简单、更高效。
生产环境中的数据库迁移:
工具:
对于我们在生产环境中的数据库迁移,我们将根据所使用的设置,使用带有 sqlite3 和 PostgreSQL 驱动程序的 Django 数据库迁移。这将允许我们在不丢失数据的情况下进行数据库架构更改。您可以在此处了解更多关于 Django 数据库迁移的信息:https://docs.djangoproject.com/en/3.2/topics/migrations/
演讲者笔记:
我们的演讲者将讨论在生产环境中迁移数据库的过程,并探索如何使用 DevOps 实践来实现数据库迁移。
安全性/模糊测试:
工具:
为了确保我们应用程序的安全性,我们将使用 PythonFuzz 进行安全测试和模糊测试。PythonFuzz 是一个基于 Python 的模糊测试工具,旨在查找代码中的错误和漏洞。您可以在此处了解更多关于 PythonFuzz 的信息:https://github.com/python-security/pyfuzz
演讲者笔记:
我们的演讲者将讨论 Web 应用程序安全测试和模糊测试的重要性,并逐步介绍使用 DevOps 实践实施安全测试和模糊测试的过程。
备份/恢复程序:
工具:
为了确保我们应用程序的可靠性和可用性,我们将使用 Django Database Backup 来设置备份和恢复程序。Django Database Backup 是一个 Django 扩展,提供了一种备份和恢复数据库的简单方法。您可以在此处了解更多关于 Django Database Backup 的信息:https://django-dbbackup.readthedocs.io/en/stable/
演讲者笔记:
我们将讨论 Web 应用程序备份和恢复程序的重要性,并逐步介绍使用 DevOps 实践设置和测试备份和恢复程序的过程。
法语
Webapp :
演讲者笔记 :
我们的演讲者将介绍我们将要构建和部署的 Web 应用程序,解释其目的以及与 DevOps 工作流程的相关性。
构建与测试 :
演讲者笔记 :
我们将逐步介绍构建和测试应用程序的过程,强调测试的重要性以及它如何融入 DevOps 工作流程。
虚拟机配置 :
演讲者笔记 :
我们的演讲者将讨论为托管应用程序配置虚拟机的过程,解释可用的不同选项以及如何为您的需求选择最佳选项。
数据库配置 :
演讲者笔记 :
我们将讨论为应用程序配置数据库的过程,并探索可用的不同选项。
部署 :
演讲者笔记 :
我们的演讲者将引导我们完成将应用程序部署到虚拟机的过程,并解释自动化在部署中的重要性。
负载均衡器 :
演讲者笔记 :
我们将讨论负载均衡对 Web 应用程序的重要性,并逐步介绍为应用程序设置负载均衡器的过程。
自定义域名 :
演讲者笔记 :
我们的演讲者将引导我们完成为应用程序设置自定义域名的过程,解释品牌和用户体验的重要性。
崩溃恢复能力 :
演讲者笔记 :
我们将讨论 Web 应用程序崩溃恢复能力的重要性,并探索如何使用 DevOps 实践来实现它。
日志记录与监控 :
演讲者笔记 :
我们的演讲者将讨论 Web 应用程序日志记录和监控的重要性,并逐步介绍为应用程序设置日志记录和监控的过程。
新需求带来的更新 :
演讲者笔记 :
我们将讨论根据新需求更新应用程序的过程,并解释 DevOps 实践如何使此过程更简单、更高效。
生产环境中的数据库迁移 :
演讲者笔记 :
我们的演讲者将讨论在生产环境中迁移数据库的过程,并探索如何使用 DevOps 实践来实现数据库迁移。
安全性/模糊测试 :
演讲者笔记 :
我们的演讲者将讨论 Web 应用程序安全测试和模糊测试的重要性,并逐步介绍使用 DevOps 实践实施安全测试和模糊测试的过程。
备份/恢复程序 :
演讲者笔记 :
我们将讨论 Web 应用程序备份和恢复程序的重要性,并逐步介绍使用 DevOps 实践设置和测试备份和恢复程序的过程。

