Help us understand the problem. What is going on with this article?

Oracle無料ティアでDjango+Nginx+uWSGIでサーバを立ててみる

More than 1 year has passed since last update.

Oracle Cloudで常時無料サービスが開始されたので使ってみた。
構成は、Django+nginx+uWSGI+Oracle Database+Oracle Linux

以下の3つの環境を作ってみたので、その時の備忘録。

  • ローカルの開発環境
  • ローカルでDockerを使った開発環境
  • コンピュート・インスタンスでの本番環境

とりあえず、Djangoの雛形アプリにアクセスできるまでの簡易なので、
SSL対応などは省いてます。

Oracle Cloudの常時無料サービス(無料ティア)について

新しく常時無料で利用できるようになったサービスたち。
Oracle Cloud無償ティア | オラクル | Oracle 日本

利用できるのは、以下のようなもの。

  • データベース ... 20GBを2つまで
  • コンピュート ... 仮想マシン。1/8 OCPU・1GBを2つまで
  • ストレージ ... 合計100GBの2つのブロック・ボリューム。10GBのオブジェクト・ストレージ

ほかにもロードバランサや監視・通知などある。

仮想マシンもデータベースも1アカウントにつき2つまでなので、
1サービスであれば、ステージング環境と本番環境を用意できそう。


とりあえずDBを作ってみる

トップ画面から。

oracle_1.png

名前とAdminのパスワードを設定する。
Always FreeもONにしておく。

oracle_2.png

「Autonomous Databaseの作成」をクリックすると、プロビジョンがはじまる。
プロビジョンが終わるとこんな感じに。

スクリーンショット 2019-11-10 15.59.16.png

WebブラウザでDBにアクセスしてみる

SQL Developer Webからアクセスできる。

「DB接続」>「アプリケーション接続」>「SQL Developer Web」にある。
「アクセスURL」をコピーして、ブラウザに貼り付け。

oracle_3.png

ログイン画面が表示されるので、DBを作ったときのパスワードを入力。
アカウントは「admin」

スクリーンショット 2019-11-10 16.00.58.png

ログインできるとこんな感じ

スクリーンショット 2019-11-10 16.01.15.png


ローカルの開発環境を作ってみる

とりあえず、開発用にローカル環境でpython manage.py runserverできるようにする。
ローカルの環境はmacOS Mojave(10.14.6)

まずは、Djangoの雛形を作成する

# pythonのバージョンは3.7.3
$ python3 -V
Python 3.7.3

# ディレクトリの作成
$ mkdir sample
$ cd sample/

# 仮想環境の作成
$ python3 -m venv venv
$ source venv/bin/activate

# djangoのインストール
$ pip install --upgrade pip
$ pip install django

# djangoプロジェクトの作成
$ django-admin startproject myproject
$ cd myproject
$ python manage.py migrate

# 起動
$ python manage.py runserver

これでとりあえず、デフォルトのデータベース(SQLite)で立ち上がるとこまで完成。

ローカルでOracleDBを使えるようにする

Oracle Instant Clientのインストール

OracleDBを使うためには、Oracle Instant Clientが必要なので、
以下からダウンロードしてインストールする。
Oracle Instant Client Downloads

Macだったので、「Instant Client for macOS (Intel x86)」の「Basic Light Package」を選択

## インストールするディレクトリを作成
$ sudo mkdir -p /opt/oracle

## インストールしたファイルを展開
$ sudo unzip ~/Downloads/instantclient-basiclite-macos.x64-19.3.0.0.0dbru.zip -d /opt/oracle

## ライブラリを参照できるように${HOME}/libにリンクを追加
$ mkdir ~/lib
$ ls -s /opt/oracle/instantclient_19_3/libclntsh.dylib ~/lib/
$ cp /opt/oracle/instantclient_19_3/lib* ~/lib/
環境変数にインストールした場所を設定
echo "export ORACLE_HOME=/opt/oracle/instantclient_19_3" >> ~/.bashrc
source ~/.bashrc
認証情報の配置

Oracle Cloudの「Autonomous Database」>「Autonomous Databaseの詳細」にある
「DB接続」からウォレットをダウンロードしてくる。

oracle_4.png

ファイル名は「Wallet_<データベース名>.zip」。
今回はデータベース名がsampleなので、Wallet_sample.zipとなる。

## 認証ファイルを配置するディレクトリを作成
$ mkdir -p /opt/oracle/instantclient_19_3/network/admin

## ダウンロードしたウォレットを展開して配置
$ sudo unzip ~/Downloads/Wallet_sample.zip -d ${ORACLE_HOME}/network/admin
Archive:  ~/Downloads/Wallet_sample.zip
  inflating: /opt/oracle/instantclient_19_3/network/admin/cwallet.sso  
  inflating: /opt/oracle/instantclient_19_3/network/admin/tnsnames.ora  
  inflating: /opt/oracle/instantclient_19_3/network/admin/truststore.jks  
  inflating: /opt/oracle/instantclient_19_3/network/admin/ojdbc.properties  
  inflating: /opt/oracle/instantclient_19_3/network/admin/sqlnet.ora  
  inflating: /opt/oracle/instantclient_19_3/network/admin/ewallet.p12  
  inflating: /opt/oracle/instantclient_19_3/network/admin/keystore.jks
cx_Oracle(pythonライブラリ)のインストール

Oracle Databaseのpythonライブラリをインストールする

$ pip install cx_Oracle
settings.pyの設定

settings.pyをOracleように変更。
NAMEには、TNS名のどれかを指定する。

oracle_4.png

今回は一番上のsample_HIGHを選択。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': 'sample_HIGH',
        'USER': 'admin',
        'PASSWORD': '<DB作成時に入力したパスワード>',
    }
}

マイグレーションをもう一度実行してみて、接続できるか確認。

$ python manage.py migrate

マイグレーションが成功すると、Webブラウザ上のSQL Developerでも確認できる。

スクリーンショット 2019-11-10 16.35.58.png

これで、とりあえず、開発できるようになった(´ω`)


ローカルでDockerを使った開発環境を作ってみる

実際にデプロイする際は、NginxとuWSGIを利用するので、
それを試せる環境をDockerで構築する。

Django側の変更

nginx+uWSGIで動かすために、いくつか変更。

1. STATIC_ROOTとALLOWED_HOSTS設定

settings.pyを以下の感じに変更。
ログファイルも出るように変更。

-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ["127.0.0.1"]

 ...

 STATIC_URL = '/static/'
+STATIC_ROOT = os.path.join(BASE_DIR, "static/")

+# for logging
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+
+    'formatters': {
+        'standard': {
+            'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
+            'datefmt': "%d/%b/%Y %H:%M:%S"
+        },
+    },
+    'handlers': {
+        'file': {
+            'level': 'INFO',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': 'django.log',
+            'maxBytes': 50000,
+            'backupCount': 2,
+            'formatter': 'standard',
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['file'],
+            'level': 'DEBUG',
+            'propagate': True,
+        },
+    },
+}

2. staticディレクトリを作成&配置

manage.pyと同じ場所に作成し、
django-adminのcssとかを配置

$ mkdir static

$ python manage.py collectstatic

Docker用の資材を配置

# Docker用の資材の配置場所を作成
$ mkdir docker

# 資格情報の配置
$ mkdir docker/wallet
$ unzip ~/Downloads/Wallet_sample.zip -d docker/wallet/
Archive:  ~/Downloads/Wallet_sample.zip
  inflating: wallet/cwallet.sso      
  inflating: wallet/tnsnames.ora     
  inflating: wallet/truststore.jks   
  inflating: wallet/ojdbc.properties  
  inflating: wallet/sqlnet.ora       
  inflating: wallet/ewallet.p12      
  inflating: wallet/keystore.jks     

# NginxやuWSGIの設定ファイルは以下に配置
$ mkdir docker/conf
$ touch docker/conf/requirements.txt
$ touch docker/conf/myproject_nginx.conf
$ touch docker/conf/myproject_uwsgi.ini
$ touch docker/conf/uwsgi.service

# Dockerfireとdocker-compose.ymlを配置
$ touch docker/Dockerfile
$ touch docker-compose.yml

ディレクトリ的にはこんな感じ。

.
├── docker/
│   ├── conf/
│   │   ├── myproject_nginx.conf
│   │   ├── myproject_uwsgi.ini
│   │   └── uwsgi.service
│   ├── wallet
│   │   ├── ...
│   │   └── tnsnames.ora
│   ├── Dockerfile
│   └── requirements.txt
├── myproject/
│   ├── myproject/
│   │   ├── settings.py
│   │   └── wsgi.py
│   ├── static/
│   └── manage.py
├── venv/
└── docker-compose.yml

各ファイルの中身は以下の感じ。

docker-compose.yml
version: '2'

services:
  web:
    build: "./docker"
    volumes: # djangoアプリを/var/www配下にマウント
      - ./myproject:/var/www/myproject
    ports: # 80および8000ポートを開けておく
      - "80:80"
      - "8000:8000"
    # systemctlを使うので特権を有効にしておく
    privileged: true
    command: /sbin/init
docker/Dockerfile
# Oracle Cloud Infrastructureでも
# OracleLinuxを使うのでoraclelinuxのイメージを使う
FROM oraclelinux:7

### ENV
ENV ORACLE_HOME "/usr/lib/oracle/18.3"


### INSTALL ORACLE DATABASE
# oracle-instantclientを利用するために、2つリポジトリを有効化
RUN yum install -y oracle-release-el7 oracle-softwarecollection-release-el7
RUN yum install -y oracle-instantclient18.3-basiclite
RUN echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf

RUN mkdir -p ${ORACLE_HOME}/network/admin
COPY wallet/* ${ORACLE_HOME}/network/admin/


### INSTALL PYTHON
# python3-develを利用するために、ol7_optional_latestを有効化
RUN yum-config-manager --enable ol7_optional_latest
RUN yum install -y python3 python3-devel gcc


### CREATE VIRTUAL ENV
RUN mkdir /var/www/
RUN mkdir /var/www/myproject

WORKDIR /var/www/

RUN python3 -m venv venv

# 作成した仮想環境(venv)にactivateする
ENV PATH="/var/www/venv/bin:$PATH"
COPY requirements.txt /var/www/
RUN pip install -r requirements.txt

#### INSTALL NGINX
RUN yum install -y nginx

COPY conf/myproject_nginx.conf /etc/nginx/conf.d/ 
RUN systemctl enable nginx

RUN chown -R nginx.nginx /var/www
RUN chmod 755 /var/www

### SETUP uWSGI Emperor mode
RUN mkdir /etc/uwsgi
RUN mkdir /etc/uwsgi/vassals
COPY conf/myproject_uwsgi.ini /etc/uwsgi/vassals

# uWSGIのログディレクトリを作成
RUN mkdir /var/log/uwsgi
RUN chown -R nginx:nginx /var/log/uwsgi

# uWSGIをサービスに登録
COPY conf/uwsgi.service /etc/systemd/system/
RUN systemctl enable uwsgi
docker/conf/requirements.txt
Django==2.2.7
cx-Oracle==7.2.3
uWSGI==2.0.18
docker/conf/myproject_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
    # myproject_uwsgi.iniで設定したsocketファイルを指定
    # unix://<socketファイルのパス>
    server unix:///var/www/myproject.sock;
}

# configuration of the server
server {
    listen      80;
    # IPアドレスを指定。ローカルなので、127.0.0.1を設定
    server_name 127.0.0.1;
    charset     utf-8;

    # Django static
    location /static {
        alias /var/www/myproject/static;
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        include     uwsgi_params;
        uwsgi_pass  django;
    }
}
docker/conf/myproject_uwsgi.ini
[uwsgi]

# Djangoプロジェクトのパスを指定
chdir           = /var/www/myproject
# Djangoプロジェクトのwsgi.pyを指定
module          = myproject.wsgi
# venvのパスを指定
home            = /var/www/venv
# process-related settings: master
master          = true
# maximum number of worker processes
processes       = 10
# socketファイルののパス
socket          = /var/www/myproject.sock
# socketファイルのユーザと権限を設定
chown-socket    = nginx:nginx
chmod-socket    = 666
# clear environment on exit
vacuum          = true
# logfile
logto           = /var/log/uwsgi/%n.log
docker/conf/uwsgi.service
[Unit]
Description=uWSGI Emperor
After=syslog.target

[Service]
User=nginx
Group=nginx

# 環境変数の設定
Environment="ORACLE_HOME=/usr/lib/oracle/18.3"
Environment="LD_LIBRARY_PAT=${ORACLE_HOME}/client64/lib:$LD_LIBRARY_PATH"
Environment="PATH=$PATH:${ORACLE_HOME}/client64/lib"

# EmperorモードでuWSGIを実行。venvにあるuwsgiを使う
ExecStart=/var/www/venv/bin/uwsgi --master --emperor /etc/uwsgi/vassals --die-on-term --uid nginx --gid nginx --logto /var/log/uwsgi/emperor.log
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target

Dockerを起動

# dockerを立ち上げ
$ docker-compose up -d

これでうまくビルドされて立ち上がれば、
http://127.0.0.1にアクセスできる。

myproject_nginx.confserver_nameで、127.0.0.1を指定しているので、
http://127.0.0.1じゃないとDjangoアプリにアクセスできないので注意。

http://localhostだと、myproject_nginx.confの設定が適用されず、
nginxのデフォルトページが表示される。

よく使うログインとか停止とかはこんな感じ。
# コンテナにログイン
$ docker-compose exec web /bin/bash

# 停止
$ docker-compose stop

# 削除
$ docker-compose rm

# Dockerfile ビルド
$ docker-compose build

# Dockerfile ビルド(キャッシュなし)
$ docker-compose build --no-cache

# コンテナをせんぶ削除
$ docker rm `docker ps -a -q`
うまくいかないときにみるところ

以下の場所にログファイルが出力されるので見てみる。

  • /var/log/messages ... systemdのログ
  • /var/log/nginx/error.log ... nginxのエラーログ
  • /var/log/uwsgi/emperor.log ... uWSGI Emperorのログ
  • /var/log/uwsgi/myproject_uwsgi.log ... myproject_uwsgi.iniのログ
  • /var/www/myproject/django.log ... Djangoプロジェクトのログ

あとは、「パスが正しいか」「権限、オーナーが正しいか」などを見てみるといいかも。


コンピュート・インスタンスで公開してみる

仮想インスタンスの作成

ここから選択。

oracle_5.png

こんな感じで入力。
パブリックIPアドレスの割当」を選択しておく。

oracle_6.png

ちゃんと「パブリックIPアドレスの割当」を選択していると、
ここにIPアドレスが表示される

oracle_7.png

デフォルトのユーザはopcなので、
こんな感じで、sshでログインできる。

$ ssh opc@<IPアドレス>

セキュリティルールを設定

HTTP(ポート80)でアクセスできるようにセキュリティルールを設定する
ただ、セキュリティルールを設定する場所は少しわかりにくい。。

仮想インスタンスの詳細にアクセスして、
「仮想クラウド・ネットワーク」を選択

oracle_8.png

左下に「ネットワーク・セキュリティ・グループ」を選択。
「ネットワーク・セキュリティ・グループの作成」を選択すると、追加できるようになる。

oracle_9.png

「名前」と「コンパートメント」に作成を設定

oracle_10.png

ルールの追加を以下のように設定して、「作成」をクリック

oracle_11.png

これで作成できたので、仮想インスタンスの詳細にもどって、
「ネットワーク・セキュリティ・グループ」の「編集」を選択

oracle_12.png

さっき作ったセキュリティグループを設定

スクリーンショット 2019-11-11 0.19.14.png

環境構築

Dockerfileでやったような感じで、
Django+nginx+uWSGIな環境を構築してく。

DockerイメージのOracleLinuxとは違い、

  1. リポジトリが最初から有効化されている
  2. SELinuxが有効化されている

という感じなので、ちょっと変更が必要。

資材を仮想インスタンスに送る

Dockerのときに使った資材を仮想インスタンスに送る。

$ scp -r docker opc@<IPアドレス>:~/
$ scp -r myproject/ opc@<IPアドレス>:~/

送信したら、ログインして確認。

$ ssh opc@<IPアドレス>

$ pwd
/home/opc

$ ls 
docker  myproject

ログイン後のディレクトリ構成はこんな感じ

/home/opc
├── docker/
│   ├── conf/
│   │   ├── myproject_nginx.conf
│   │   ├── myproject_uwsgi.ini
│   │   └── uwsgi.service
│   ├── wallet
│   │   ├── ...
│   │   └── tnsnames.ora
│   ├── Dockerfile
│   └── requirements.txt
├── myproject/
│   ├── myproject/
│   │   ├── settings.py
│   │   └── wsgi.py
│   ├── static/
│   └── manage.py
├── venv/
└── docker-compose.yml
設定ファイルの変更

IPアドレスと127.0.0.1にしていたので変更する。

~/docker/conf/myproject_nginx.conf
  server {
-     server_name 127.0.0.1;
+     server_name <IPアドレス>;
  }
~/myproject/myproject/settings.py
-ALLOWED_HOSTS = ["127.0.0.1"]
+ALLOWED_HOSTS = ["<IPアドレス>"]
環境構築の実施
$ sudo -s

### INSTALL ORACLE DATABASE
$ yum install -y oracle-instantclient18.3-basiclite
$ echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf

$ mkdir -p /usr/lib/oracle/18.3/network/admin
$ /home/opc/docker/wallet/* /usr/lib/oracle/18.3/network/admin/


### INSTALL PYTHON
$ yum install -y python3 python3-devel gcc


### CREATE VIRTUAL ENV
$ mkdir /var/www/
$ cp -r /home/opc/myproject /var/www

$ cd /var/www/

$ python3 -m venv venv

# 作成した仮想環境(venv)にactivateする
$ source venv/bin/activate
$ pip install -r /home/opc/docker/requirements.txt

#### INSTALL NGINX
$ yum install -y nginx

$ cp /home/opc/docker/conf/myproject_nginx.conf /etc/nginx/conf.d/ 
$ systemctl enable nginx

$ chown -R nginx.nginx /var/www
# $ chmod 755 /var/www

### SETUP uWSGI Emperor mode
$ mkdir -p /etc/uwsgi/vassals
$ cp /home/opc/docker/conf/myproject_uwsgi.ini /etc/uwsgi/vassals

# uWSGIのログディレクトリを作成
$ mkdir /var/log/uwsgi
$ chown -R nginx:nginx /var/log/uwsgi

# uWSGIをサービスに登録
$ cp /home/opc/docker/conf/uwsgi.service /etc/systemd/system/
$ systemctl enable uwsgi

##### ここから仮想インスタンス独自の設定

### Firewallの設定
# httpを追加する
$ firewall-cmd --permanent --add-service=http
# firewallを再起動して変更を反映
$ systemctl restart firewalld.service

### SELinuxの設定
$ restorecon -RF /var/www

### サービスの起動
$ systemctl restart nginx
$ systemctl restart uwsgi

一度、http://<IPアドレス>にアクセスして確認してみる。
エラーページが出ていたら、以下を実行

# 監査ログを確認
$ cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx
# ポリシーファイルを作成
$ cat /var/log/audit/audit.log | audit2allow -M nginx
# ポリシーファイルを適用
$ semodule -i nginx.pp

これで、http://<IPアドレス>にアクセスして、
Djangoの画面が表示されて、django-adminの画面が操作できればOK

おわりに

とりあえず、ローカルとインスタンス上の環境が作れたので、
色々することはできそう(´ω`)

SSL対応、権限周りなど、本番としては足りないところがあるので、
そのあたりは他の記事を参照ください〜ヽ(=´▽`=)ノ

こんなのつくってます!!

積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!
積読ハウマッチは、Nuxt.js+Firebaseで開発してます!

もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ

要望・感想・アドバイスなどあれば、
公式アカウント(@MemoryLoverz)や開発者(@kira_puka)まで♪

参考にしたサイトさま

kira_puka
フリーのエンジニア / 今はNuxt.jsが多め / いつかFlutterをやりたい 受託開発をしながら、アプリ・Webサービス・ゲームを個人開発 Kotlin/Python/Swift/Unity/Java/Haskell/DDD
https://memory-lovers.com
admin-guild
「Webサービスの運営に必要なあらゆる知見」を共有できる場として作られた、運営者のためのコミュニティです。
https://admin-guild.slack.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away