Рубрики
Без рубрики

Gitlab CI / CD-трубопровод для развертывания вашего Python API с Postgres на Heroku

Сегодня мы построим спокойную API, используя Python Flask, SQLalchemy, используя Postgres в качестве нашей базы данных, TE … Помечено с Docker, Python, DevOps, Tutorial.

Сегодня мы построим RESTFLAY API с помощью Python Flask , Sqlalchemy, используя Postgres Как наша база данных, тестирование с использованием Python Unittest , CI/CD-трубопровод на Gitlab и Развертывание Героку Отказ

С нашего предыдущего поста мы продемонстрировали настройку пользовательского бегуна Gitlab на вашем собственном сервере для GitLab CI.

Соответствующие сообщения

  • Настройка базового трубопровода CI на GitLab
  • Настройте трубопровод GitLab CI/CD для развертывания вашего Python API в Heroku (этот пост)
  • Настройте бегун GitLab CI на своем собственном сервере

Heroku

Если у вас уже нет учетной записи, Heroku Предлагайте 5 бесплатных приложений в их учетной записи свободного уровня. Как только вы создали свою учетную запись, создайте 2 приложения. Я назвал мою Flask-API-постановка и Flask-API-Prod Отказ

Вы можете создать приложения через CLI или интернет-пользовательский интерфейс, от UI, он будет выглядеть более или меньше, подобное этому:

Выберите имя приложения и проверьте, доступен ли имя, затем выберите Создать. Обратите внимание на имя и конфиг, как мы будем использовать его в нашем .gitlab-ci.yml. config:

Heroku API ключ

Чтобы разрешить развертывание приложений к Heroku из GitLab, нам нужно создать ключ API на Heroku и сохранить конфигурацию в GitLab.

Перейти к вашему Heroku Dashboard , выберите Настройки учетной записи, выделите раздел клавиши API и создайте ключ API.

Перейдите к вашему репозиторию GitLab, выберите Настройки, CI/CD, затем выберите Переменные Введите клавишу: Heroku_api_key И секрет ключа API в значение и выберите перемезу сохранения.

Мы ссылаемся на эту переменную из наших шагов развертывания.

Heroku Postgres дополняет

Heroku предлагает дополнительное дополнение Postgres, чтобы активировать: выберите свое приложение, выберите ресурсы, поиск дополнения Heroku Postgres Выберите и выберите HOBBY DEV Free версию и выберите «Предоставление».

Наш код приложения

Клонируйте ваш репозиторий, затем начнем с создания нашего API колба. Обратите внимание, что это больше на GitLab CI/CD, чем в деталях в приложении колба.

Создайте файлы, которые нам понадобится:

$ touch app.py config.cfg requirements.txt tests.py Procfile

Начнем с заполнения нашей конфигурации для нашего приложения Flask: config.cfg.

#SQLALCHEMY_DATABASE_URI='sqlite:///database.db'
SQLALCHEMY_TRACK_MODIFICATIONS=False

Наше приложение для колбы: приложение

Обратите внимание, что мы используем Flask-Heroku, с этим пакетом Heroku автоматически узнает вашу конфигурацию для вашей базы данных с использованием переменных среды. Поэтому, если у вас есть дополнение Postgres, вам не нужно указывать местоположение вашей базы данных.

Если вы хотите использовать SQLite, вы можете удалить зрелищую атмосферу Heroku и беспокойство Sqlalchemy_database_uri Недвижимость в вашем config.cfg.

from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_heroku import Heroku
from passlib.hash import sha256_crypt
from datetime import datetime

app = Flask(__name__)
app.config.from_pyfile('config.cfg')
heroku = Heroku(app)
db = SQLAlchemy(app)
ma = Marshmallow(app)

## --Database Models--
class Member(db.Model):
    __tablename__ = 'members'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    email = db.Column(db.String(255), unique=True, nullable=False)
    username = db.Column(db.String(50), unique=True)
    password_hash = db.Column(db.String(100))
    firstname = db.Column(db.String(50), unique=False)
    lastname = db.Column(db.String(50), unique=False)
    registered_on = db.Column(db.DateTime, nullable=False)

class MemberSchema(ma.ModelSchema):
    class Meta:
        model = Member
        fields = ('id', 'username', 'email')

member_schema = MemberSchema(strict=True, only=('id', 'username'))
members_schema = MemberSchema(strict=True, many=True)

## --Views--
@app.route('/')
def index():
    return jsonify({'message': 'ok'}), 200

# list users
@app.route('/api/user', methods=['GET'])
def list_users():
    all_users = Member.query.all()
    result = members_schema.dump(all_users)
    return jsonify(result.data)

# get user
@app.route('/api/user/', methods=['GET'])
def get_user(id):
    user = Member.query.get(id)
    result = member_schema.dump(user)
    return jsonify(result.data)

# add user
@app.route('/api/user', methods=['POST'])
def add_user():
    email = request.json['email']
    username = request.json['username']
    password_hash = sha256_crypt.encrypt(request.json['password'])
    firstname = request.json['firstname']
    lastname = request.json['lastname']
    new_user = Member(email=email, username=username, password_hash=password_hash, firstname=firstname, lastname=lastname, registered_on=datetime.utcnow())
    try:
        db.session.add(new_user)
        db.session.commit()
        result = member_schema.dump(Member.query.get(new_user.id))
        return jsonify({'member': result.data})
    except:
        db.session.rollback()
        result = {'message': 'error'}
        return jsonify(result)

# update user
@app.route('/api/user/', methods=['PUT'])
def update_user(id):
    user = Member.query.get(id)
    username = request.json['username']
    email = request.json['email']
    user.email = email
    user.username = username
    db.session.commit()
    return member_schema.jsonify(user)

# delete user
@app.route('/api/user/', methods=['DELETE'])
def delete_user(id):
    user = Member.query.get(id)
    db.session.delete(user)
    db.session.commit()
    return jsonify({'message': '{} has been deleted'.format(user.username)})

if __name__ == '__main__':
    app.run()

Наши тесты: тесты

import unittest
import app as myapi
import json
import sys

class TestFlaskApi(unittest.TestCase):
    def setUp(self):
        self.app = myapi.app.test_client()

    def test_hello_world(self):
        response = self.app.get('/')
        self.assertEqual(
            json.loads(response.get_data().decode(sys.getdefaultencoding())),
            {"message": "ok"}
        )

if __name__ == '__main__':
    unittest.main()

Наши требования к файлу: требования

Click==7.0
Flask==1.0.2
flask-heroku==0.1.9
flask-marshmallow==0.9.0
Flask-SQLAlchemy==2.3.2
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
marshmallow==2.17.0
marshmallow-sqlalchemy==0.15.0
passlib==1.7.1
psycopg2-binary==2.7.6.1
six==1.12.0
SQLAlchemy==1.2.15
Werkzeug==0.14.1

Наш Procfile для Heroku: ProCFile

web: gunicorn app:app

И, наконец, наша конфигурация GitLab-Ci, которая будет включать в себя нашу сборку, тестирование и развертывание шагов. Как только получено обломок для мастера, конвейер будет активирован. Обратите внимание, что наш шаг развертывания производства является ручным триггером.

Наш конфиг для .gitlab-ci.yml Отказ Примечание, чтобы заменить ваши имена приложений Heroku.

image: rbekker87/build-tools:latest

stages:
  - ver
  - init
  - tests
  - deploy

ver:
  stage: ver
  script:
    - python --version
    - whoami

init:
  stage: init
  script:
    - apk add postgresql-dev --no-cache
    - pip install psycopg2-binary
    - pip install -r requirements.txt

run_tests:
  stage: tests
  script:
    - apk add postgresql-dev --no-cache
    - pip install psycopg2-binary
    - pip install -r requirements.txt
    - python tests.py

deploy_staging:
  stage: deploy
  script:
    - git remote add heroku https://heroku:$HEROKU_API_KEY@git.heroku.com/flask-api-staging.git
    - git push heroku master
    - echo "Deployed to Staging Server https://flask-api-staging.herokuapp.com"
  environment:
    name: staging
    url: https://flask-api-staging.herokuapp.com/
  only:
    - master

deploy_production:
  stage: deploy
  script:
    - git remote add heroku https://heroku:$HEROKU_API_KEY@git.heroku.com/flask-api-prod.git
    - git push heroku master
    - echo "Deployed to Production Server https://flask-api-prod.herokuapp.com"
  environment:
    name: production
    url: https://flask-api-prod.herokuapp.com/
  when: manual
  only:
    - master

Отправить в Gitlab:

После того, как все заполнено, наставьте свои изменения, совершите свою работу и подтолкнитесь к мастеру:

$ git add .
$ git commit -m "blogpost demo commit"
$ git push origin master

Как только код будет нажата на MASTER, GitLab заберет его и запускает трубопровод для запуска.

Трубопроводы GitLab

Перейдите к GitLab, выберите CI/CD -> трубопроводы, вы должны увидеть бегущий трубопровод, выберите его, тогда вы должны увидеть обзор всех ваших заданий:

Если все прошло, вы должны увидеть Прошло Статус, как показано выше.

Вы заметите, что промежуточная среда была развернута. Теперь вы можете сделать некоторые тестирование, и когда вы будете довольны этим, вы можете выбрать кнопку воспроизведения, которая будет развернуть до производства на приборной панели трубопроводов.

Создание таблиц на Postgres

Прежде чем мы сможем взаимодействовать с нашим API, нам нужно предоставить таблицы Postgres из моделей базы данных, которые мы написали в нашем приложении.

Откройте раковину Python на Heroku и инициализируйте таблицы:

$ heroku run python -a flask-api-prod
>>> from app import db
>>> db.create_all()
>>> exit()

Тестирование API:

Теперь, когда все работает и работает, пришло время проверить нашу API.

Список пользователей:

$ curl https://flask-api-staging.herokuapp.com/api/user
[]

Создать пользователя:

$ curl -H 'Content-Type: application/json' -XPOST https://flask-api-staging.herokuapp.com/api/user -d '{"username": "ruanb", "password": "pass", "email": "r@r.com", "firstname": "ruan", "lastname": "bekker"}'
{
  "member": {
    "id": 1,
    "username": "ruanb"
  }
}

Список пользователей:

$ curl -H 'Content-Type: application/json' -XGET https://flask-api-staging.herokuapp.com/api/user
[
  {
    "email": "ruan@r.com",
    "id": 1,
    "username": "ruanb"
  }
]

Обновите адрес электронной почты пользователя:

$ curl -H 'Content-Type: application/json' -XPUT https://flask-api-staging.herokuapp.com/api/user/1 -d '{"username": "ruanb", "email": "ruan@r.com"}'
{
  "id": 1,
  "username": "ruanb"
}

Получить один пользователь:

$ curl -H 'Content-Type: application/json' -XGET https://flask-api-staging.herokuapp.com/api/user/1
{
  "email": "ruan@r.com",
  "id": 1,
  "username": "ruanb"
}

Удалить пользователя:

$ curl -H 'Content-Type: application/json' -XDELETE https://flask-api-staging.herokuapp.com/api/user/1
{
  "message": "ruanb has been deleted"
}

Исправление проблем

У меня были некоторые проблемы с Heroku, где один был после того, как я развернул, я получил эту ошибку в журналах Heroku:

code=H14 desc="No web processes running" method=GET path="/"

Мне просто пришлось масштабировать мою сеть Dyno до 1:

$ heroku ps:scale web=1 -a flask-api-staging
Scaling dynos... done, now running web at 1:Free

Посмотрите на их Документация Если вам нужна помощь с Heroku CLI.

А для устранения неполадок в Dyno вы можете работать в нем, запустив это:

$ heroku ps:exec -a flask-api-staging

Я серьезно копаю GitLab-CI и с этой демонстрацией вы можете увидеть, насколько легко настроить CI/CD-трубопровод на GitLab и развернуть их в Heroku.

Ресурсы:

Код для этой демонстрации доступен по адресу: gitlab.com/rbekker87/demo-cicd-flask-heroku

Для больше сообщений в блоге на Gitlab, посмотрите на мой Gitlab. Категория на blog.ruanbekker.com

Спасибо

Пожалуйста, не стесняйтесь показывать поддержку, Обмен Этот пост, посетите меня в Ruan.dev Или следовать за мной в Twitter в @ruanbekker.

Оригинал: “https://dev.to/ruanbekker/gitlab-ci-cd-pipeline-to-deploy-your-python-api-with-postgres-on-heroku-12g3”