LightsailでCentOS&Docker&Djangoのサイトを構築する

CentOS,Django,Docker,Lightsail

以下、完全に自分流のやり方ですが、動作はします。

この記事の前提条件

・linuxにssh接続できること
・linux操作の基本を知っていること
・bashのシェルスクリプトでhello worldくらいは理解していること
・vimの操作ができること
・Docker操作とDocker-composeを理解していること

環境変数を使うために.bash_profileを編集する

以下、Lightsailにssh接続してから、実行して下さい。

// 環境変数を設定する (export する変数)は、.bash_profileに書くと捗りそう。
$ echo export work_id="10" >> ~/.bash_profile
$ echo export workDirPath="/srv/10" >> ~/.bash_profile
又は
$ vim ~/.bash_profile
(iで編集を開始する)
(次の行を追加する)
export work_id=10
export workDirPath=/srv/${work_id}
(escを押して、:wqを押して保存して閉じる)

$ cat ~/.bash_profile

// 再起動せずに、反映させる
$ source ~/.bash_profile

// 確認
$ echo ${work_id} && echo ${workDirPath}
10
/srv/10

以上の環境変数の設定でわかるように、この記事ではlinuxのディレクトリの中の/srvという場所にファイルを展開していきます。

docker-compose.ymlでdjangoコンテナ、nginxコンテナ、mysqlコンテナを作成

/srvを利用したいので、srvディレクトリの所有者を変更します。

// 事前確認
$ ls -al /
drwxr-xr-x.  2 root root    6  4月 11  2018 srv

// /srvをmkdirするために、chownで所有者をrootからcentosにする
$ sudo chown -R centos:centos /srv

// 事後確認
$ ls -al /
drwxr-xr-x.  2 centos centos    6  4月 11  2018 srv

vimでシェルスクリプトを作成します。以下のオレンジの文字からオレンジの文字までコピーして、vimで開いたファイルにペーストして下さい。
bash -c ・・・コピペのため、ワンライナーで書きたいのでcオプションを利用してます。

// (環境変数の設定&ディレクトリ作成&ファイル作成)
$ bash -c "mkdir ${workDirPath} && vim ${workDirPath}/make1.sh"

(iで編集を開始する)
#!bin/bash

# まずは環境変数が設定されているかの確認。
if [ -z "${work_id}" ]; then
  echo "\$work_idが空です。"
  exit 0
fi
if [ -z "$workDirPath" ]; then
  echo "\$workDirPathが空です。"
  exit 0
fi

mkdir -p ${workDirPath}/django

# DjangoコンテナのDockerfileの作成
cat <<EOS > ${workDirPath}/django/Dockerfile
FROM python
RUN pip install -U pip && \
    mkdir /DjangoContainer
WORKDIR /DjangoContainer
COPY requirements.txt /DjangoContainer/requirements.txt
RUN pip install -r requirements.txt
EOS

# requirements.txt(pipでインストールするライブラリを記録するファイル)を作成
cat <<EOS > ${workDirPath}/django/requirements.txt
Django==2.0.4
uwsgi==2.0.17
PyMySQL==0.8.0
pytest
EOS

# Dockerfileの作成より上で実行する
mkdir -p ${workDirPath}/mysql/conf.d

# mySQLコンテナのDockerfileの作成
cat <<EOS > ${workDirPath}/mysql/Dockerfile
FROM mysql:5.6

RUN apt-get update && \
    apt-get install -y locales && \
    rm -rf /var/lib/apt/lists/* && \
    echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen && \
    locale-gen ja_JP.UTF-8
ENV LC_ALL ja_JP.UTF-8
EOS

# my.cnfの作成
# 文字化けさせないためだったり、全角文字を入力できるようにするためだったりの設定
cat <<EOS > ${workDirPath}/mysql/conf.d/my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
[client]
default-character-set=utf8mb4
EOS


mkdir -p ${workDirPath}/mysql/init

# mySQLの起動時のテーブルの作成
cat <<EOS > ${workDirPath}/mysql/init/1_comment.sql
create database if not exists web_db;

use web_db;

create table t_Comment (
   ID int,
   Text varchar(255),
   Name varchar(255),
   VoteDate Date
);

INSERT INTO t_Comment (ID, Text, Name) VALUES (1, 'はじめまして','森蘭丸');
INSERT INTO t_Comment (ID, Text, Name) VALUES (2, 'ういヤツよ','織田信長');
EOS

# docker-compose.ymlの作成
cat <<EOS > ${workDirPath}/docker-compose.yml
version: '3'

services:
  mysql_i${work_id}:
    build: ${workDirPath}/mysql
    container_name: ${work_id}_mysql
    restart: always
    #↓MySQLの文字コードの設定。日本語入力。
    #command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - "33${work_id}:3306"
    #  - "3306:3306"
    environment:
      MYSQL_DATABASE: web_db
      MYSQL_USER: username
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: root
      TZ: "Asia/Tokyo"
    volumes:
      # 永続化のディレクトリ
      - ${workDirPath}/mysql/data:/var/lib/mysql
      # 公式のmysqlイメージの場合、docker-entrypoint-initdb.dに置かれているファイルは
      # docker起動時に自動で実行される。つまり、初期化のディレクトリ。
      - ${workDirPath}/mysql/init:/docker-entrypoint-initdb.d
      # 設定
      - ${workDirPath}/mysql/conf.d:/etc/mysql/conf.d
  django_i${work_id}:
    build: ${workDirPath}/django
    tty: true
    container_name: ${work_id}_django
    restart: always
    command: >
      /bin/bash -c "chmod 755 /DjangoContainer/start.sh &&
      bash /DjangoContainer/start.sh"
    volumes:
    - ${workDirPath}/django:/DjangoContainer
    #ports:
    #- "81${work_id}:81${work_id}"
    expose:
    - "81${work_id}"
    depends_on:
    - mysql_i${work_id}
  nginx_i${work_id}:
    image: nginx:1.17.2
    container_name: ${work_id}-nginx
    restart: always
    ports:
    - "80:80"
    #- "81${work_id}:8010"
    depends_on:
    - django_i${work_id}
    volumes:
    - ${workDirPath}/nginx/conf.d:/etc/nginx/conf.d
    - ${workDirPath}/nginx/uwsgi_params:/etc/nginx/uwsgi_params
    #- ${workDirPath}/nginx/public:/usr/share/nginx/html

networks:
  default:
    external:
      name: shared
EOS

mkdir -p ${workDirPath}/nginx/conf.d

#=====================
# my_nginx.confの作成
#=====================
cat <<EOS > ${workDirPath}/nginx/conf.d/my_nginx.conf
upstream djangoo {
    ip_hash;
    server ${work_id}_django:81${work_id};
}

server {
    listen       80;
    #server_name  localhost;

    location / {
        uwsgi_pass  djangoo;
        include     /etc/nginx/uwsgi_params;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
#versionを隠す
server_tokens off;
#ログの保存ファイルの指定
#access_log  /var/log/nginx/access_2.log  main;
#error_log  /var/log/nginx/error_2.log  warn;
#↑これをコメントインするとdocker-composeで停止した状態になる。謎。
# 但し、docker restart ${work_id}-nginx をすると動く。後回し。
# また、access.logとerror.logにすると、なぜか記録されない。不思議。
EOS

#=====================
# uwsgi_paramsの作成
#=====================
cat <<EOS > ${workDirPath}/nginx/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  REQUEST_SCHEME     \$scheme;
uwsgi_param  HTTPS              \$https if_not_empty;

uwsgi_param  REMOTE_ADDR        \$remote_addr;
uwsgi_param  REMOTE_PORT        \$remote_port;
uwsgi_param  SERVER_PORT        \$server_port;
uwsgi_param  SERVER_NAME        \$server_name;
EOS

# uwsgiの設定ファイルを作成
cat <<EOS > ${workDirPath}/django/uwsgi.ini
[uwsgi]
socket = :81${work_id}
#socket = /DjangoContainer/uwsgi.sock
module = config.wsgi
#wsgi-file = /DjangoContainer/config/wsgi.py
#logto = /DjangoContainer/config/uwsgi.log
py-autoreload = 1
EOS

# djangoのコンテナが起動したときに実行するシェルファイルを作成
cat <<EOS > ${workDirPath}/django/start.sh
#!/bin/bash

django-admin startproject config .
uwsgi --ini /DjangoContainer/uwsgi.ini
EOS

docker-compose -f ${workDirPath}/docker-compose.yml up -d
(escを押して、:wqを押して保存して閉じる)

シェルスクリプトを実行して、Dockerを立ち上げる

// シェルファイルを実行(エラーが出ます)
$ bash ${workDirPath}/make1.sh
ERROR: Network shared declared as external, but could not be found. Please create the network manually using `docker network create shared` and try again.

// コレを実行すると、エラーが治ります。
$ docker network create shared

// Dockerを立ち上げる
$ docker-compose -f ${workDirPath}/docker-compose.yml up -d

// dockerの状態を確認する
$ docker ps -a

ブラウザからDjangoの表示を確認する

// ディレクトリ以下を一括でパーミッション変更
// Macで開発する場合は、これをやらない感じ
// yamutyaというユーザをMacで作っていなく、別ユーザでMacを利用しているため
// 同時に所有権が変更されたかも確認する
$ sudo chown -R $USER:$USER ${workDirPath}/django
$ sudo chmod -R g+w ${workDirPath}/django
$ sudo chown -R $USER:$USER ${workDirPath}/mysql
$ ls -l ${workDirPath}/django ${workDirPath}/mysql

    // ${workDirPath}/mysql/data のディレクトリの所有者が元のままだった。なぜだ。

$ vim ${workDirPath}/django/config/settings.py

//(iで編集を開始する。)
//(↓該当部分をこのように変更する)
ALLOWED_HOSTS = ["*"]

LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
//(↑該当部分をこのように変更する)
//(escを押して、:wqを押して保存して閉じる)

ブラウザからlocalhost、又はグローバルIPアドレスにアクセスして、Djangoのロケットの表示がされていたらOKです。
Lightsailで確認する場合は、ALLOWED_HOSTS = [“*"]をやっていないと、Djangoのエラーページが表示されます。但し、アスタリスクだと攻撃を受ける恐れがあるので、アスタリスクの代わりに独自ドメインを指定するほうが、セキュリティ的によいです。

ちなみにこの段階ではまだ、トップページは作成されていない状態です。

感想

LightsailのCentosでポート80がcloseのまま、dockerのnginxのコンテナを起動したら、ポート80は自動でopenになりました。iptablesもfirewalldもインストールしてません。つまり、LightsailのCentOSのデフォルト状態です。この状態でDockerのnginxを起動するだけで、ポート80をしっかりopenしてくれていました。