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

読了目安:21分

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)まで♪

参考にしたサイトさま

Originally published at qiita.com
ツイッターでシェア
みんなに共有、忘れないようにメモ

きらぷか@積読ハウマッチ/SSSAPIなど

フリーエンジニア/今はNuxt.js/いつかFlutter 受託&アプリ/Webサービス/ゲームを #個人開発 CS修士→SIer/R&D→フリー #paiza はAランクで満足/AtCoderしたい #DMでお仕事募集はお休み中 Kotlin/Python/Swift/Unity/Java/Haskell/DDD

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント