├── .gitignore ├── LICENSE ├── README.md ├── bin ├── container_start.sh ├── initialize_project.sh ├── pipenv_lock.sh └── pytest.sh ├── docker-compose.yml ├── envs └── db.env ├── nginx ├── mime.types └── nginx.conf ├── postgres ├── Dockerfile └── docker-entrypoint-initdb.d │ └── init-db.sh └── web ├── Dockerfile ├── Pipfile └── pytest.ini /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # vscode 92 | .vscode/* 93 | *.code-workspace -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Shinya Ota 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dockerize Django Environment 2 | 3 | ## Specification 4 | 5 | * WSGI 6 | * [Gunicorn](https://gunicorn.org/) 7 | * HTTP server 8 | * [nginx](https://nginx.org/en/) 9 | * Database 10 | * [PostgreSQL](https://www.postgresql.org/) 11 | 12 | ## How to use 13 | 14 | 1. Build your Docker environment 15 | 16 | ```sh 17 | docker-compose build 18 | ``` 19 | 20 | 2. Create the Django project using the docker-compose command. 21 | 22 | ```sh 23 | docker-compose run web django-admin.py startproject yourproject . 24 | ``` 25 | 26 | 3. In your project directory, edit the yourproject/settings.py file. 27 | 28 | ```python 29 | DATABASES = { 30 | 'default': { 31 | 'ENGINE': 'django.db.backends.postgresql', 32 | 'NAME': 'your_db_name', 33 | 'USER': 'your_db_user', 34 | 'PASSWORD': 'your_db_password', 35 | 'HOST': 'db', 36 | 'PORT': 5432, 37 | } 38 | } 39 | ``` 40 | 41 | 4. In `web/yourproject/settings.py`, add the line at the bottom of it. 42 | 43 | ```python 44 | STATIC_ROOT = STATIC_ROOT = os.path.join(BASE_DIR, 'static') 45 | ``` 46 | 47 | 5. Install Admin app. In `web/yourproject/settings.py`, add line `django.contrib.admin` 48 | 49 | ```python 50 | INSTALLED_APPS = [ 51 | 'django.contrib.admin', 52 | 'django.contrib.auth', 53 | 'django.contrib.contenttypes', 54 | 'django.contrib.sessions', 55 | 'django.contrib.messages', 56 | 'django.contrib.staticfiles', 57 | ] 58 | ``` 59 | 60 | 6. Run the `docker-compose up` command again 61 | 62 | ```sh 63 | sh bin/container_start.sh 64 | ``` 65 | 66 | 7. Go ahead, create your app! 67 | 68 | ```sh 69 | docker-compose exec web python manage.py startapp yourapp 70 | ``` 71 | 72 | 8. Initilize your database 73 | 74 | ```sh 75 | docker-compose exec web python manage.py migrate 76 | ``` 77 | 78 | 9. Enable `Model` 79 | 80 | - Define your model class in `yourapps/models.py` 81 | - Add line `yourapps.apps.YourappsConfig` in `web/app/settings.py` of `INSTALLED_APPS` 82 | 83 | ```python 84 | INSTALLED_APPS = [ 85 | 'yourapps.apps.YourappsConfig', 86 | 'django.contrib.admin', 87 | 'django.contrib.auth', 88 | 'django.contrib.contenttypes', 89 | 'django.contrib.sessions', 90 | 'django.contrib.messages', 91 | 'django.contrib.staticfiles', 92 | ] 93 | ``` 94 | - do migrations 95 | ```python 96 | docker exec web python manage.py makemigrations yourapps 97 | ``` 98 | 99 | 10. Initilize Django admin 100 | 101 | ```sh 102 | docker-compose exec -it web python manage.py createsuperuser 103 | ``` 104 | 105 | 11. Collecting staticfiles 106 | 107 | ```sh 108 | docker-compose run web python manage.py collectstatic --noinput 109 | ``` 110 | -------------------------------------------------------------------------------- /bin/container_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker-compose up -d --build 4 | 5 | # Collect static files 6 | echo "Collect static files" 7 | docker-compose exec web python manage.py collectstatic --noinput 8 | 9 | # Apply database migrations 10 | echo "Apply database migrations" 11 | docker-compose exec web python manage.py migrate 12 | 13 | docker-compose logs -f 14 | -------------------------------------------------------------------------------- /bin/initialize_project.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker-compose run web django-admin.py startproject $1 . 3 | docker-compose rm -s -------------------------------------------------------------------------------- /bin/pipenv_lock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker-compose exec web pipenv lock -------------------------------------------------------------------------------- /bin/pytest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker-compose exec web pytest -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | restart: always 5 | build: ./web 6 | expose: 7 | - "8000" 8 | depends_on: 9 | - db 10 | command: gunicorn test.wsgi -b 0.0.0.0:8000 11 | volumes: 12 | - ./web:/usr/src/app 13 | - ./web/static/:/usr/src/app/static 14 | env_file: 15 | - ./envs/db.env 16 | nginx: 17 | restart: always 18 | image: nginx 19 | ports: 20 | - "80:80" 21 | volumes: 22 | - "./nginx/:/etc/nginx/" 23 | - /web/static 24 | depends_on: 25 | - web 26 | db: 27 | restart: always 28 | build: ./postgres 29 | ports: 30 | - 5432:5432 31 | volumes: 32 | - ./postgres/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d/ 33 | - pgdata:/var/lib/postgresql/data 34 | env_file: 35 | - ./envs/db.env 36 | volumes: 37 | pgdata: 38 | driver: "local" -------------------------------------------------------------------------------- /envs/db.env: -------------------------------------------------------------------------------- 1 | POSTGRES_PASSWORD=postgres 2 | POSTGRES_USER=postgres 3 | -------------------------------------------------------------------------------- /nginx/mime.types: -------------------------------------------------------------------------------- 1 | types { 2 | text/html html htm shtml; 3 | text/css css; 4 | text/xml xml rss; 5 | image/gif gif; 6 | image/jpeg jpeg jpg; 7 | application/x-javascript js; 8 | text/plain txt; 9 | text/x-component htc; 10 | text/mathml mml; 11 | image/png png; 12 | image/x-icon ico; 13 | image/x-jng jng; 14 | image/vnd.wap.wbmp wbmp; 15 | application/java-archive jar war ear; 16 | application/mac-binhex40 hqx; 17 | application/pdf pdf; 18 | application/x-cocoa cco; 19 | application/x-java-archive-diff jardiff; 20 | application/x-java-jnlp-file jnlp; 21 | application/x-makeself run; 22 | application/x-perl pl pm; 23 | application/x-pilot prc pdb; 24 | application/x-rar-compressed rar; 25 | application/x-redhat-package-manager rpm; 26 | application/x-sea sea; 27 | application/x-shockwave-flash swf; 28 | application/x-stuffit sit; 29 | application/x-tcl tcl tk; 30 | application/x-x509-ca-cert der pem crt; 31 | application/x-xpinstall xpi; 32 | application/zip zip; 33 | application/octet-stream deb; 34 | application/octet-stream bin exe dll; 35 | application/octet-stream dmg; 36 | application/octet-stream eot; 37 | application/octet-stream iso img; 38 | application/octet-stream msi msp msm; 39 | audio/mpeg mp3; 40 | audio/x-realaudio ra; 41 | video/mpeg mpeg mpg; 42 | video/quicktime mov; 43 | video/x-flv flv; 44 | video/x-msvideo avi; 45 | video/x-ms-wmv wmv; 46 | video/x-ms-asf asx asf; 47 | video/x-mng mng; 48 | } 49 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | user nobody nogroup; 4 | pid /tmp/nginx.pid; 5 | error_log /tmp/nginx.error.log; 6 | 7 | events { 8 | worker_connections 1024; 9 | accept_mutex off; 10 | } 11 | 12 | http { 13 | include /etc/nginx/mime.types; 14 | default_type application/octet-stream; 15 | access_log /tmp/nginx.access.log combined; 16 | sendfile on; 17 | 18 | upstream app_server { 19 | server web:8000 fail_timeout=0; 20 | } 21 | 22 | server { 23 | listen 80 default; 24 | client_max_body_size 4G; 25 | server_name localhost:8000; 26 | 27 | keepalive_timeout 5; 28 | 29 | location /static/ { 30 | alias /usr/src/app/static/; 31 | } 32 | 33 | location / { 34 | try_files $uri @proxy_to_app; 35 | } 36 | 37 | location @proxy_to_app { 38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 39 | proxy_set_header Host $http_host; 40 | proxy_set_header X-Real-IP $remote_addr; 41 | proxy_redirect off; 42 | proxy_pass http://app_server; 43 | } 44 | 45 | error_page 500 502 503 504 /500.html; 46 | location = /500.html { 47 | root /path/to/app/current/public; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:10 2 | 3 | COPY docker-entrypoint-initdb.d/init-db.sh /docker-entrypoint-initdb.d/ 4 | RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 5 | ENV LANG ja_JP.utf8 6 | -------------------------------------------------------------------------------- /postgres/docker-entrypoint-initdb.d/init-db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --password "$POSTGRES_PASSWORD" <<-EOSQL 5 | -- For auth 6 | 7 | -- For sessions 8 | 9 | EOSQL 10 | -------------------------------------------------------------------------------- /web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-alpine 2 | ENV PYTHONUNBUFFERED 1 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | COPY Pipfile /usr/src/app/ 6 | RUN apk update \ 7 | && apk add --virtual build-tools gcc python3-dev musl-dev \ 8 | && apk add postgresql-dev 9 | RUN pip install pipenv 10 | RUN pipenv lock --pre 11 | RUN pipenv install --system --dev 12 | RUN pipenv install --system --deploy 13 | RUN apk del build-tools 14 | ADD . /usr/src/app/ 15 | -------------------------------------------------------------------------------- /web/Pipfile: -------------------------------------------------------------------------------- 1 | [dev-packages] 2 | flake8 = ">=3.9.2" 3 | pytest = ">=6.2.4" 4 | pytest-django = ">=4.4.0" 5 | pytest-sugar = ">=0.9.4" 6 | pytest-factoryboy = ">=2.1.0" 7 | 8 | [packages] 9 | django = "<=3.2.5" 10 | psycopg2 = "<=2.9.1" 11 | gunicorn = "<=20.10" 12 | 13 | -------------------------------------------------------------------------------- /web/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | # https://pytest-django.readthedocs.io/en/latest/tutorial.html 3 | DJANGO_SETTINGS_MODULE = yourproject.settings 4 | python_files = tests.py test_*.py *_tests.py 5 | --------------------------------------------------------------------------------