在Docker环境下的Web3层构造~nginx、django、PostgreSQL的协同配合~

首先

此次要创建的东西。

Group_3.png

筹备工作

– 可以公开访问的服务器(在本篇文章中使用了EC2实例。选择的操作系统是Amazon Linux 2。)
– 安装Python 3(在本篇文章中使用了版本为3.8.9。后半部分有通过pyenv安装的步骤说明。)

验证 docker-compose 的运行(直到启动 nginx)。

安装 Docker

登录EC2实例并使用SSH执行以下命令安装Docker。
并且设置Docker可以在启动时自动启动,并且启用。

sudo yum install -y docker
sudo systemctl start docker
sudo systemctl enable docker
sudo docker info # 確認

将ec2-user添加到docker组中。

通过这个方法,您可以在不使用sudo的情况下使用docker命令。
此外,如同docker官方文档所述,可以完成以下操作。

如果在虚拟机上进行测试,为了使更改生效,可能需要重新启动虚拟机。

添加群组后重新启动实例。

sudo usermod -aG docker $USER
cat /etc/group | grep docker # 確認
sudo reboot # 再起動

安装Docker Compose

检查Docker官方文档,确定版本(本次使用1.29.2)。

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose version # 確認

通过docker-compose确认容器的启动

使用Docker Compose 获取nginx镜像并显示测试页面。

version: '3.7'
services:
    nginx:
        container_name: nginx
        image: nginx:latest
        ports:
            - 80:80

执行以下指令来启动容器。

docker-compose up -d
Screen Shot 2021-06-20 at 12.21.32.png
docker-compose down

建立三层架构

准备nginx容器(Web服务器)

目录结构

容器/
├ Django/
│ └ …
├ Nginx/
└ 配置/
└ nginx.conf
└ uwsgi参数
├ docker-compose.yml

添加volume的分配和依赖关系。

version: '3.7'
services:
    nginx:
        container_name: nginx
        image: nginx:latest
        volumes: # add
            - ./nginx/conf:/etc/nginx/conf.d # add
            - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params # add
        ports:
            - 80:80
        depends_on: # add
            - django # add

创建 nginx.conf 文件。
根据 upstream 指令中的描述,将通信流量设置到 Django 容器的8000端口上。

(Chinese translation)

upstream django {
    server django:8000;
}

server {
    listen 80;
    location / {
        uwsgi_pass django;
        include /etc/nginx/uwsgi_params;
    }
}

创建用于WSGI通信所需的uwsgi_params(参考)。

uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;

准备django容器(应用服务器)。

目录结构

容器/
├ django/
│ └ 启动
│ └ setuser.sh
│ └ startup.sh
│ └ uwsgi
│ └ uwsgi.ini
│ └ Dockerfile
│ └ requirements.txt
├ nginx/
│ └ …
├ docker-compose.yml

为了能够接收nginx容器发送过来的通信请求,需要在Django容器中创建uwsgi.ini文件。

[uwsgi]
socket = :8000
module = djangoapp.wsgi
wsgi-file = /app/app/wsgi.py
logto = /wsgi/wsgi.log
py-autoreload = 1

创建一个用于构建Django容器镜像的Dockerfile。

FROM python:3
WORKDIR /app
COPY requirements.txt /app
RUN pip install -r requirements.txt
COPY . /app

创建一个在Django容器中所需的Python模块列表。

django
psycopg2
uwsgi

在Django容器中创建一个执行的shell脚本(startup.sh, setuser.sh)。
创建用户,并执行uwsgi.ini文件。

source /startup/setuser.sh # setuser.sh を実行する
uwsgi --ini /wsgi/uwsgi.ini # uwsgi.ini の設定をもとに uwsgi を実行する
#!/bin/bash -e
SHELL_NAME='setuser.sh'
echo "[$SHELL_NAME] START"

# setup group
if getent group "$GROUP_ID" > /dev/null 2>&1; then
    echo "[$SHELL_NAME] GROUP_ID '$GROUP_ID' already exists."
else
    echo "[$SHELL_NAME] GROUP_ID '$GROUP_ID' does NOT exist. So execute [groupadd -g \$GROUP_ID \$GROUP_NAME]."
    groupadd -g $GROUP_ID $GROUP_NAME
fi

# setup user
if getent passwd "$USER_ID" > /dev/null 2>&1; then
    echo "[$SHELL_NAME] USER_ID '$USER_ID' already exists."
else
    echo "[$SHELL_NAME] USER_ID '$USER_ID' does NOT exist. So execute [useradd -m -s /bin/bash -u \$USER_ID -g \$GROUP_ID \$USER_NAME]."
    useradd -m -s /bin/bash -u $USER_ID -g $GROUP_ID $USER_NAME
fi

echo "[$SHELL_NAME] FINISH"

给startup目录下的所有文件添加执行权限。

chmod +x -R ~/dev/3l_on_docker/django/startup/

首先,在主机端创建Django项目。为此,首先在主机端安装Django。

pip install django

在Django目录下创建Django项目。
本次项目名称将设为djangoapp。

django-admin startproject djangoapp

创建项目后,在Django目录中会自动生成一个名为djangoapp的文件夹。

默认情况下,拒绝所有来自外部的通信,需要对setting.py进行修改。

...

ALLOWED_HOSTS = ['*']

...

这次设置了允许外部所有通信的”*”选项。

使用docker-compose up -d命令启动容器,并访问EC2的公共IP地址。

Screen Shot 2021-06-24 at 9.54.07.png

只要能看到类似上面的 Django 测试页面就可以。

创建样品应用程序

既经看到了测试页面,从这里开始显示自己创建的页面。
首先,在主机端创建一个应用程序。

python manage.py startapp sampleapp

在sampleapp文件夹的根目录下创建urls.py。

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

访问 http://[IP地址]/[应用名称],如果可以确认看到 “你好,世界。你在投票索引页面。”,那就可以了。

数据库布局(编辑 models.py 文件)

class User(models.Model):
    user_name = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class FigurePaths(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    figure_url = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    like_point = models.IntegerField(default=0)
INSTALLED_APPS = [
    'instalikeapp.apps.InstalikeappConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
python manage.py makemigrations sampleapp

在migration目录下会创建一个0001_initial.py文件。

使用docker exec -it bash命令进入django容器,并执行sqlmigrate和migrate命令,以完成向数据库添加数据的准备工作。

[ec2-user@ip-10-0-1-89 djangoapp]$ docker exec -it django bash
root@87e83722b47a:/app# python manage.py sqlmigrate sampleapp 0001
root@87e83722b47a:/app# python manage.py migrate

准备PostgreSQL容器(数据库服务器)。

在PostgreSQL容器中添加配置。

version: '3.7'
services:
    nginx:
        container_name: nginx
        image: nginx:latest
        volumes:
            - ./nginx/conf:/etc/nginx/conf.d
            - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
        ports:
            - 80:80
        depends_on:
            - django

    django:
        container_name: django
        build: ./django
        command: bash -c /startup/startup.sh
        volumes:
            - ./django/uwsgi:/wsgi
            - ./django/djangoapp:/app
            - ./django/startup:/startup
        ports:
            - 8000:8000
        environment:
            - USER_ID=1000
            - GROUP_ID=1000
            - USER_NAME=ec2-user
            - GROUP_NAME=ec2-user
        depends_on: # add
            - postgresql # add

    postgresql: # add
        image: postgres:latest # add
        container_name: postgresql # add
        environment: # add
            - POSTGRES_DB=instalikeapp_db # add
            - POSTGRES_USER=user # add
            - POSTGRES_PASSWORD=password # add
        volumes: # add
            - ./pgdata:/var/lib/postgresql/data # add
        ports: # add
            - 5432:5432 # add

重新启动容器。

docker-compose restart

尝试使用Django容器内的Python解释器将数据插入数据库。

可以参考Django教程以获取详细信息。
进入Django容器,并通过Python解释器向数据库输入数据。

docker exec -it django bash
root@87e83722b47a:/app# python manage.py shell
>>> from instalikeapp.models import User, FigurePaths

使用以下命令登录到 PostgreSQL 数据库。

psql -d myapp -U USERNAME -h localhost
Screen Shot 2021-06-24 at 13.17.23.png

额外奖励

通过pyenv安装Python 3系。

sudo yum install git
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bashrc
source ~/.bashrc
sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y
pyenv install 3.8.9
pyenv global 3.8.9

将CSS应用到Django网站中

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static') # add

将静态文件复制到项目的静态目录下的static文件夹中。

python manage.py collectstatic
server {
    listen 80;

    location / {
        uwsgi_pass django;
        include /etc/nginx/uwsgi_params;
    }

    location /static/ {
        root    /app/;
    }
}
广告
将在 10 秒后关闭
bannerAds