mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 00:57:02 +02:00
Merge pull request #35 from cisagov/sspj/proof-of-concept
Tiny bit of Docker
This commit is contained in:
commit
2fa2f33c3b
12 changed files with 327 additions and 1 deletions
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# License
|
||||||
|
|
||||||
|
As a work of the [United States government](https://www.usa.gov/), this project is in the public domain within the United States of America.
|
||||||
|
|
||||||
|
Additionally, we waive copyright and related rights in the work worldwide through the CC0 1.0 Universal public domain dedication.
|
||||||
|
|
||||||
|
## CC0 1.0 Universal Summary
|
||||||
|
|
||||||
|
This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode).
|
||||||
|
|
||||||
|
### No Copyright
|
||||||
|
|
||||||
|
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of their rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
|
||||||
|
|
||||||
|
You can copy, modify, distribute, and perform the work, even for commercial purposes, all without asking permission.
|
||||||
|
|
||||||
|
### Other Information
|
||||||
|
|
||||||
|
In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights.
|
||||||
|
|
||||||
|
Unless expressly stated otherwise, the person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. When using or citing the work, you should not imply endorsement by the author or the affirmer.
|
21
README.md
21
README.md
|
@ -1,7 +1,26 @@
|
||||||
# .gov documentation
|
# .gov documentation
|
||||||
|
========================
|
||||||
|
|
||||||
Welcome to .gov! This is a repository to house work on the current .gov site(s).
|
Welcome to .gov! This is a repository to house work on the current .gov site(s).
|
||||||
|
|
||||||
## Onboarding
|
## Onboarding
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
Code is located in the [src](./src/) directory.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### Architectural Decision Records
|
||||||
|
|
||||||
|
Architectural Decision Records (ADR) are located in [docs/architecture/decisions](./docs/architecture/decisions).
|
||||||
|
|
||||||
|
### Product Goals
|
||||||
|
|
||||||
|
These are located in [docs/product](./docs/product).
|
||||||
|
|
||||||
|
### Research Artifacts
|
||||||
|
|
||||||
|
Including some helpful scanning tools. These are located in [docs/research](./docs/research)
|
25
docs/architecture/decisions/0002-docker-for-development.md
Normal file
25
docs/architecture/decisions/0002-docker-for-development.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# 2. Docker for development
|
||||||
|
|
||||||
|
Date: 2022-08-09
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Docker is widely accepted at TTS currently and in the development community at large. It works well with cloud.gov and is very portable to other cloud solutions.
|
||||||
|
|
||||||
|
The [Federal Audit Clearinghouse](https://github.com/GSA-TTS/FAC) project is a similar project to ours, from which we are taking many examples for reuse. FAC uses Docker.
|
||||||
|
|
||||||
|
Other options include using virtual machines or installing dependencies directly onto the host system. The first is not widely used at TTS; the second tends to cause problems with dependency management.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
To include a Dockerfile and docker-compose file.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
We intend to deploy using containerized images; therefore, use of Docker on local will give the closest approximation to higher environments.
|
||||||
|
|
||||||
|
A greater technical burden may be placed on new employees during onboarding, if they have not already installed Docker and learned to use it.
|
35
docs/architecture/decisions/0003-django.md
Normal file
35
docs/architecture/decisions/0003-django.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# 3. Django
|
||||||
|
|
||||||
|
Date: 2022-08-09
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Django is a web framework based on Python that has been in active development since 2005.
|
||||||
|
|
||||||
|
It follows a very standard MVC architecture (made popular by Ruby on Rails), although in Django parlance, a “view” is a controller (whereas the views are “templates”).
|
||||||
|
|
||||||
|
It comes with a robust object relational mapper for database access and includes a built-in admin interface suitable for simple use cases.
|
||||||
|
|
||||||
|
The [Federal Audit Clearinghouse](https://github.com/GSA-TTS/FAC) project is a similar project to ours, from which we are taking many examples for reuse. FAC uses Django.
|
||||||
|
|
||||||
|
Numerous other web frameworks exist in many languages, such as Ruby, PHP, Perl, Go, Elixir, etc. Other web frameworks exist in Python, such as Twisted and Flask.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
To use Django.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Django is well documented and approachable, even for people with limited programming experience.
|
||||||
|
|
||||||
|
We will have a dependency on the health of the Django project and the Python ecosystem at large.
|
||||||
|
|
||||||
|
Python is an interpreted language and will not have the same performance as compiled languages. Django is slower than its less featureful Python competitors (while being faster than Ruby on Rails, its nearest other-language competitor).
|
||||||
|
|
||||||
|
The job market for Django developers is currently (8/2022) strong, with 7,000 open positions on a popular career site.
|
||||||
|
|
||||||
|
Moving away from Django at a future point would require a complete rewrite of the codebase.
|
29
docs/architecture/decisions/0004-docker-base-image.md
Normal file
29
docs/architecture/decisions/0004-docker-base-image.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# 4. Docker base image
|
||||||
|
|
||||||
|
Date: 2022-08-09
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
In containerized builds, it is rare to start from scratch. The project’s Dockerfile should specify a base image from which to build.
|
||||||
|
|
||||||
|
The [python page on Docker Hub](https://hub.docker.com/_/python) has a discussion of what various image variants contain.
|
||||||
|
|
||||||
|
Python images can be scoped to specific versions, such as 3.8.6, or to more generic versions, such as 3. There is a slim variant for smaller image size and variants scoped to specific versions of Debian.
|
||||||
|
|
||||||
|
Alpine is a popular base image due to its small size and fast build times. However, it may not be the best choice for Python projects, due to its use of musl over glibc. Here’s a [blog post explaining this](https://pythonspeed.com/articles/alpine-docker-python/).
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
To use python:3.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
The python:3 image may or may not be secure enough for the long term needs of the project.
|
||||||
|
|
||||||
|
Using python:3 ensures that minor version upgrades will be automatically performed each time the image is built. The consequence is that the code may break unexpectedly, if a minor version introduces an incompatibility. The risk of this is low, as the Python team strives for semantic versioning, but is not zero.
|
||||||
|
|
||||||
|
Likewise, not pinning to the underlying Debian release ensures that the image will use the latest stable release at each build, with the same risk and benefit trade-off.
|
25
docs/architecture/decisions/0005-postgresql.md
Normal file
25
docs/architecture/decisions/0005-postgresql.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# 5. PostgreSQL
|
||||||
|
|
||||||
|
Date: 2022-08-09
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Our choices of which database engine to use are presently limited by our desire to use cloud.gov for deployment.
|
||||||
|
|
||||||
|
Cloud.gov supports MySQL, PostgreSQL, and Oracle.
|
||||||
|
|
||||||
|
Oracle may be subject to licensing fees.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
To use PostgreSQL.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
All three options are approximately equally capable. The number of CVEs filed against each project differs, but not by any order of magnitude.
|
||||||
|
|
||||||
|
The advanced administrative features of each database are not available in cloud.gov, so there is little reason to prefer one option over any other.
|
9
src/Dockerfile
Normal file
9
src/Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
FROM python:3
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y postgresql-client
|
||||||
|
|
||||||
|
COPY Pipfile Pipfile
|
||||||
|
COPY Pipfile.lock Pipfile.lock
|
||||||
|
|
||||||
|
RUN pip install pipenv
|
||||||
|
RUN pipenv install --system --dev
|
8
src/Pipfile
Normal file
8
src/Pipfile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[[source]]
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
django = "*"
|
||||||
|
|
43
src/Pipfile.lock
generated
Normal file
43
src/Pipfile.lock
generated
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "8b5635a4f7b069ae6661115b9eaa15466f7cd96794af5d131735a3638be101fb"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.python.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"asgiref": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4",
|
||||||
|
"sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==3.5.2"
|
||||||
|
},
|
||||||
|
"django": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
|
||||||
|
"sha256:032f8a6fc7cf05ccd1214e4a2e21dfcd6a23b9d575c6573cacc8c67828dbe642"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.1"
|
||||||
|
},
|
||||||
|
"sqlparse": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
|
||||||
|
"sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==0.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
21
src/README.md
Normal file
21
src/README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Registrar
|
||||||
|
========================
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
If you're new to Django, see [Getting Started with Django](https://www.djangoproject.com/start/) for an introduction to the framework.
|
||||||
|
|
||||||
|
### Local Setup
|
||||||
|
|
||||||
|
* Install Docker <https://docs.docker.com/get-docker/>
|
||||||
|
* Initialize the application:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker-compose build
|
||||||
|
```
|
||||||
|
* Run the server: `docker-compose up`
|
||||||
|
|
||||||
|
### Update Dependencies
|
||||||
|
|
||||||
|
1. Check the [Pipfile](./src/Pipfile) for pinned dependencies and manually adjust the version numbers
|
||||||
|
1. Run `docker-compose up` and `docker-compose exec app pipenv update` to perform the upgrade and generate a new [Pipfile.lock](./src/Pipfile.lock)
|
56
src/app/docker_entrypoint.py
Normal file
56
src/app/docker_entrypoint.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
This is a Docker entrypoint that configures the container to run
|
||||||
|
as the same uid of the user on the host container, rather than
|
||||||
|
the Docker default of root. Aside from following security best
|
||||||
|
practices, this makes it so that any files created by the Docker
|
||||||
|
container are also owned by the same user on the host system.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import subprocess # nosec
|
||||||
|
|
||||||
|
HOST_UID = os.stat("/app").st_uid
|
||||||
|
HOST_USER = "james"
|
||||||
|
|
||||||
|
|
||||||
|
def does_username_exist(username):
|
||||||
|
try:
|
||||||
|
pwd.getpwnam(username)
|
||||||
|
return True
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def does_uid_exist(uid):
|
||||||
|
try:
|
||||||
|
pwd.getpwuid(uid)
|
||||||
|
return True
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if HOST_UID != os.geteuid():
|
||||||
|
if not does_uid_exist(HOST_UID):
|
||||||
|
username = HOST_USER
|
||||||
|
while does_username_exist(username):
|
||||||
|
username += "0"
|
||||||
|
home_dir = "/home/%s" % username
|
||||||
|
subprocess.check_call(
|
||||||
|
[ # nosec
|
||||||
|
"useradd",
|
||||||
|
"-d",
|
||||||
|
home_dir,
|
||||||
|
"-m",
|
||||||
|
username,
|
||||||
|
"-u",
|
||||||
|
str(HOST_UID),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
os.environ["HOME"] = "/home/%s" % pwd.getpwuid(HOST_UID).pw_name
|
||||||
|
os.setuid(HOST_UID)
|
||||||
|
os.execvp(sys.argv[1], sys.argv[1:]) # nosec
|
35
src/docker-compose.yml
Normal file
35
src/docker-compose.yml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
version: "3.0"
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./app:/app
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
working_dir: /app
|
||||||
|
entrypoint: python /app/docker_entrypoint.py
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
max_attempts: 5
|
||||||
|
environment:
|
||||||
|
# Ensure stdout and stderr are sent straight to the terminal without buffering
|
||||||
|
- PYTHONUNBUFFERED=yup
|
||||||
|
# In case we'd like to know
|
||||||
|
- RUNNING_IN_DOCKER=yup
|
||||||
|
# How to connect to Postgre container
|
||||||
|
- DATABASE_URL=postgres://user:feedabee@db/app
|
||||||
|
# Run in development mode on our local
|
||||||
|
- DJANGO_SETTINGS_MODULE=app.settings.dev
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
command: "python"
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:latest
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=app
|
||||||
|
- POSTGRES_USER=user
|
||||||
|
- POSTGRES_PASSWORD=feedabee
|
Loading…
Add table
Add a link
Reference in a new issue