Доцкер Девелопмент ВоркФлов - водич са Фласком и Постгресом

Доцкер, једна од најновијих лудости, невероватан је и моћан алат за паковање, испоруку и покретање апликација. Међутим, разумевање и подешавање Доцкера за вашу одређену апликацију може потрајати мало времена. Будући да је интернет препун концептуалних водича, нећу ићи превише дубоко концептуално о контејнерима. Уместо тога, објаснићу шта значи сваки ред који напишем и како то можете применити на вашу одређену апликацију и конфигурацију.

Зашто Доцкер?

Део сам студентске непрофитне организације која се зове Хацк4Импацт на УИУЦ-у, где развијамо техничке пројекте за непрофитне организације како бисмо им помогли да наставе са својим мисијама. Сваког семестра имамо више пројектних тимова од 5–7 студентских програмера софтвера, са различитим нивоима вештина, укључујући студенте који су завршили тек први курс информатике на факултету.

Пошто су многе непрофитне организације често тражиле веб апликације, припремио сам Фласк Боилерплате како бих тимовима омогућио да брзо покрену и покрену своје позадинске РЕСТ АПИ услуге. Уобичајене функције услужног програма, структура апликација, омотачи базе података и везе су обезбеђени заједно са документацијом за подешавање, најбољим праксама кодирања и корацима за Хероку примену.

Питања око развојног окружења и зависности

Међутим, пошто смо сваког семестра укрцавали нове програмере студентског софтвера, тимови би потрошили пуно времена на конфигурисање и решавање проблема околине. Често бисмо имали више чланова који се развијају на различитим оперативним системима и наишли на безброј проблема (Виндовс, показујем на вас). Иако су многи од тих проблема били тривијални, попут покретања исправне верзије базе података ПостгреСКЛ са правим корисником / лозинком, било је изгубљено време које је могло бити стављено у сам производ.

Уз то, написао сам документацију само за кориснике МацОС-а са само басх упутствима (имам Мац) и у основи сам оставио кориснике Виндовс-а и Линук-а да се не осуше. Могао сам да окренем неке виртуелне машине и поново документујем подешавање за сваки ОС, али зашто бих то радио ако постоји Доцкер?

Уђите у Доцкер

Помоћу Доцкера, целокупна апликација се може изоловати у контејнере који се могу преносити са машине на машину. Ово омогућава доследна окружења и зависности. Тако можете да „једном направите, покренете било где“, а програмери ће сада моћи да инсталирају само једну ствар - Доцкер - и покрену неколико команди да покрену апликацију. Новопридошли ће моћи брзо да почну да се развијају без бриге о свом окружењу. Непрофитне организације ће такође моћи брзо да уносе промене у будућности.

Доцкер има и многе друге предности, попут преносиве природе и ресурса ефикасне природе (у поређењу са виртуелним машинама) и начина на који можете безболно поставити континуирану интеграцију и брзо применити своју апликацију.

Кратак преглед основних компоненти Доцкера

Много је ресурса на мрежи који ће објаснити Доцкер боље него што могу, па их нећу претерано детаљно прегледавати. Ево сјајног блога о његовим концептима и још једног о Доцкеру. Међутим, размотрићу неке од основних компоненти Доцкера које су потребне да би се разумео остатак овог блога.

Доцкер Имагес

Доцкер слике су предлошци само за читање који описују Доцкер контејнер. Садрже специфична упутства написана у Доцкерфиле-у која дефинишу апликацију и њене зависности. Схватите их као снимак ваше апликације у одређено време. Добићете слике када их добијете docker build.

Доцкер контејнери

Доцкер контејнери су примерци Доцкерових слика. Они укључују оперативни систем, код апликације, време извршавања, системске алате, системске библиотеке итд. Можете повезати више Доцкер контејнера заједно, као што је апликација Ноде.јс у једном контејнеру који је повезан са контејнером базе података Редис. Водићете Доцкер контејнер са docker start.

Доцкер Регистри

Доцкер Регистри је место за чување и дистрибуцију Доцкерових слика. Доцкер слике ћемо користити као основне слике са ДоцкерХуб-а, бесплатног регистра који хостује сам Доцкер.

Доцкер Цомпосе

Доцкер Цомпосе је алатка која вам омогућава да истовремено направите и покренете више Доцкер слика. Уместо да покрећете исте вишеструке команде сваки пут када желите да покренете своју апликацију, све их можете радити у једној команди - једном када наведете одређену конфигурацију.

Пример Доцкера са Фласк и Постгрес

Имајући на уму све Доцкер компоненте, кренимо у постављање Доцкер развојног окружења са апликацијом Фласк користећи Постгрес као складиште података. У остатку овог блога, позваћу се на Фласк Боилерплате, спремиште које сам раније поменуо за Хацк4Импацт.

У овој конфигурацији користићемо Доцкер за изградњу две слике:

  • app - апликација Фласк послужена у луци 5000
  • postgres - база података Постгрес послужена у луци 5432

Када погледате горњи директоријум, постоје три датотеке које дефинишу ову конфигурацију:

  • Доцкерфиле - скрипта састављена од упутстава за подешавање appконтејнера. Свака наредба је аутоматска и извршава се сукцесивно. Ова датотека ће се налазити у директоријуму где сте покренули апликацију ( python manage.py runserverили python app.py, или npm startсу неки примери). У нашем случају је у горњем директоријуму (где manage.pyсе налази). Доцкерфиле прихвата Доцкер упутства.
  • .доцкеригноре - одређује које датотеке се не смеју укључити у контејнер. То је баш као .gitignoreи за Доцкер контејнере. Ова датотека је упарена са Доцкерфиле-ом.
  • доцкер-цомпосе.имл - Конфигурациона датотека за Доцкер Цомпосе. То ће нам омогућити да истовремено направимо appи postgresслике и слике, дефинишемо запремине и стање у appзависности postgresи поставимо потребне променљиве околине.

Напомена: Постоји само један Доцкерфиле за две слике, јер ћемо узети званичну Доцкер Постгрес слику са ДоцкерХуб-а! Можете да додате своју Постгрес слику тако што ћете јој написати сопствени Доцкерфиле, али нема смисла.

Доцкерфиле

Само да појасним поново, овај Доцкерфиле је за appконтејнер. Као преглед, ево целокупне Доцкерфиле датотеке - она ​​у суштини добија основну слику, прекопира апликацију, инсталира зависности и поставља одређену променљиву окружења.

FROM python:3.6
LABEL maintainer "Timothy Ko "
RUN apt-get update
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
ENV FLASK_ENV="docker"
EXPOSE 5000

Because this Flask Application uses Python 3.6, we want an environment that supports it and already has it installed. Fortunately, DockerHub has an official image that’s installed on top of Ubuntu. In one line, we will have a base Ubuntu image with Python 3.6, virtualenv, and pip. There are tons of images on DockerHub, but if you would like to start off with a fresh Ubuntu image and build on top of it, you could do that.

FROM python:3.6

I then note that I’m the maintainer.

LABEL maintainer "Timothy Ko "

Now it’s time to add the Flask application to the image. For simplicity, I decided to copy the application under the /app directory on our Docker Image.

RUN mkdir /app
COPY . /app
WORKDIR /app

WORKDIR is essentially a cd in bash, and COPY copies a certain directory to the provided directory in an image. ADD is another command that does the same thing as COPY , but it also allows you to add a repository from a URL. Thus, if you want to clone your git repository instead of copying it from your local repository (for staging and production purposes), you can use that. COPY, however, should be used most of the time unless you have a URL. Every time you use RUN, COPY, FROM, or CMD, you create a new layer in your docker image, which affects the way Docker stores and caches images. For more information on best practices and layering, see Dockerfile Best Practices.

Now that we have our repository copied to the image, we will install all of our dependencies, which is defined in requirements.txt

RUN pip install --no-cache-dir -r requirements.txt

But say you had a Node application instead of Flask — you would instead write RUN npm install. The next step is to tell Flask to use Docker Configurations that I hardcoded into config.py. In that configuration, Flask will connect to the correct database we will set up later on. Since I had production and regular development configurations, I made it so that Flask would choose the Docker Configuration whenever the FLASK_ENV environment variable is set to docker. So, we need to set that up in our app image.

ENV FLASK_ENV="docker"

Then, expose the port(5000) the Flask application runs on:

EXPOSE 5000

And that’s it! So no matter what OS you’re on, or how bad you are at following documentation instructions, your Docker image will be same as your team members’ because of this Dockerfile.

Anytime you build your image, these following commands will be run. You can now build this image with sudo docker build -t app .. However, when you run it with sudo docker run app to start a Docker Container, the application will run into a database connection error. This is is because you haven’t provisioned a database yet.

docker-compose.yml

Docker Compose will allow you to do that and build your app image at the same time. The entire file looks like this:

version: '2.1'services: postgres: restart: always image: postgres:10 environment: - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_DB} volumes: - ./postgres-data/postgres:/var/lib/postgresql/data ports: - "5432:5432" app: restart: always build: . ports: - 5000:5000 volumes: - .:/app

For this specific repository, I decided to use version 2.1 since I was more comfortable with it and it had a few more guides and tutorials on it — yeah, that’s my only reasoning for not using version 3. With version 2, you must provide “services” or images you want to include. In our case, it is app and postgres(these are just names that you can refer to when you use docker-compose commands. You call them database and api or whatever floats your boat).

Postgres Image

Looking at the Postgres Service, I specify that it is a postgres:10 image, which is another DockerHub Image. This image is an Ubuntu Image that has Postgres installed and will automatically start the Postgres server.

postgres: restart: always image: postgres:10 environment: - POSTGRES_USER=${USER} - POSTGRES_PASSWORD=${PASSWORD} - POSTGRES_DB=${DB} volumes: - ./postgres-data/postgres:/var/lib/postgresql/data ports: - "5432:5432"

If you want a different version, just change the “10” to something else. To specify what user, password, and database you want inside Postgres, you have to define environment variables beforehand — this is implemented in the official postgres Docker image’s Dockerfile. In this case, the postgres image will inject the $USER, $PASSWORD, and $DB environment variables and make them the POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB envrionment variables inside the postgres container. Note that $USER and the other environment variables injected are environment variables specified in your own computer (more specifically the command line process you are using to run the docker-compose up command. By injecting your credentials, this allows you to not commit your credentials into a public repository.

Docker-compose will also automatically inject environment variables if you have a .env file in the same directory as your docker-compose.yml file. Here’s an example of a .env file for this scenario:

USER=testusrPASSWORD=passwordDB=testdb

Thus our PostgreSQL database will be named testdb with a user called testusr with password password.

Our Flask application will connect to this specific database, because I wrote down its URL in the Docker Configurations I mentioned earlier.

Every time a container is stopped and removed, the data is deleted. Thus, you must provide a persistent data storage so none of the database data is deleted. There are two ways to do it:

  • Docker Volumes
  • Local Directory Mounts

I’ve chosen to mount it locally to ./postgres-data/postgres , but it can be anywhere. The syntax is always[HOST]:[CONTAINER]. This means any data from /var/lib/postgresql/data is actually stored in ./postgres-data.

volumes:- ./postgres-data/postgres:/var/lib/postgresql/data

We will use the same syntax for ports:

ports:- "5432:5432"

app Image

We will then define the app image.

app: restart: always build: . ports: - 5000:5000 volumes: - .:/app depends_on: - postgres entrypoint: ["python", "manage.py","runserver"]

We first define it to have restart: always. This means that it will restart whenever it fails. This is especially useful when we build and start these containers. app will generally start up before postgres, meaning that app will try to connect to the database and fail, since the postgres isn’t up yet. Without this property, app would just stop and that’s the end of it.

We then define that we want this build to be the Dockerfile that is in this current directory:

build: .

This next step is pretty important for the Flask server to restart whenever you change any code in your local repository. This is very helpful so you don’t need to rebuild your image over and over again every time to see your changes. To do this, we do the same thing we did for postgres : we state that the /app directory inside the container will be whatever is in .(the current directory). Thus, any changes in your local repo will be reflected inside the container.

volumes: - .:/app

After this, we need to tell Docker Compose that app depends on the postgres container. Note that if you change the name of the image to something else like database, you must replace that postgres with that name.

depends_on: - postgres

Finally, we need to provide the command that is called to start our application. In our case, it’s python manage.py runserver.

entrypoint: ["python", "manage.py","runserver"]

One caveat for Flask is that you must explicitly note which host (port) you want to run it in, and whether you want it to be in debug mode when you run it. So in manage.py, I do that with:

def runserver(): app.run(debug=True, host=’0.0.0.0', port=5000)

Finally, build and start your Flask app and Postgres Database using your Command Line:

docker-compose builddocker-compose up -ddocker-compose exec app python manage.py recreate_db

The last command essentially creates the database schema defined by my Flask app in Postgres.

And that’s it! You should be able to see the Flask application running on //localhost:5000!

Docker Commands

Remembering and finding Docker commands can be pretty frustrating in the beginning, so here’s a list of them! I’ve also written a bunch of commonly used ones in my Flask Boilerplate Docs if you want to refer to that.

Conclusion

Доцкер заиста омогућава тимовима да се развијају много брже захваљујући својој преносивости и доследном окружењу на различитим платформама. Иако сам Доцкер прошао само кроз развој, Доцкер се истиче када га користите за континуирану интеграцију / тестирање и у примени.

Могао бих да додам још неколико линија и имам комплетну продукцијску поставку са Нгинк-ом и Гуницорн-ом. Ако бих желео да користим Редис за кеширање сесија или као ред, могао бих то да урадим врло брзо и сви у мом тиму могли би да имају исто окружење када су обновили своје Доцкер слике.

И не само то, могао бих да завртим 20 примерака апликације Фласк за неколико секунди ако бих то желео. Хвала за читање! :)

Ако имате било каквих мисли и коментара, слободно оставите коментар испод или ми пошаљите е-маил на тк[email protected]иллиноис.еду! Такође, слободно користите мој код или га поделите са својим вршњацима!