Skip to content

KK - 12 Factor App

Π‘ΡƒΡ…ΠΎΠΉ конспСкт ΠΈ лабораторная Ρ€Π°Π±ΠΎΡ‚Π° ΠΏΠΎ курсу 12 Factor App ΠΎΡ‚ KodeKloud, Π½Π°ΠΏΠΎΠ»Π½Π΅Π½Π½ΠΎΠ΅ мыслями Π°Π²Ρ‚ΠΎΡ€Π°

Intro

12-Ρ„Π°ΠΊΡ‚ΠΎΡ€Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ - это мСтодология Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ обСспСчСния, которая опрСдСляСт ряд ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² для создания ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Ρ…, устойчивых ΠΈ Π»Π΅Π³ΠΊΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π² ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Ρ… срСдах.

Π’ΠΎΡ‚ 12 ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ 12-Ρ„Π°ΠΊΡ‚ΠΎΡ€Π½Ρ‹Π΅ прилоТСния (ΠΏΠΎ вСрсии chat-gpt):

  1. Код базируСтся Π½Π° ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Ρ… вСрсиях, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ хранятся Π² систСмС контроля вСрсий.
  2. Зависимости ΠΎΡ‚ сторонних Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ ΠΈ сСрвисов ΡƒΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ явно ΠΈ Ρ€Π°Π·Π΄Π΅Π»ΡΡŽΡ‚ΡΡ.
  3. ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ прилоТСния Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½Π° Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния.
  4. Backing сСрвисы (Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ сообщСний ΠΈ Ρ‚.Π΄.) Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΊΠ°ΠΊ присоСдиняСмыС рСсурсы.
  5. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ ΠΊΠ°ΠΊ ΠΎΠ΄ΠΈΠ½ ΠΈΠ»ΠΈ нСсколько процСссов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΡŒΠ½ΠΎ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ.
  6. Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ обСспСчСно ΠΊΠ°ΠΊ ΠΏΠΎΡ‚ΠΎΠΊ стандартного Π²Ρ‹Π²ΠΎΠ΄Π° ΠΈ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмы.
  7. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠΎΠ΄ΠΎΠ² Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π°.
  8. ΠŸΡ€ΠΎΡ†Π΅ΡΡΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π±Π΅Π· состояний ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π»Π΅Π³ΠΊΠΎ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½Ρ‹ ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΡƒΡ‰Π΅Π½Ρ‹.
  9. Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°, тСстированиС ΠΈ производство Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΡƒΡŽ срСду.
  10. Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠ³ΠΎ прилоТСния ΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π½Π° Π΄Π²Π΅ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ сущности.
  11. АдминистрированиС прилоТСния Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Ρ‡Π΅Ρ€Π΅Π· Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.
  12. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ быстрого ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ Π½Π° основС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ.

БоблюдСниС этих ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π»Π΅Π³ΠΊΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ, ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ Π² ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Ρ… срСдах.

1. Codebase (32) - (VCS)

  • Код хранится Π² VCS, для Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ с Π½ΠΈΠΌ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ
  • Бущности слСдуСт Π΄Ρ€ΠΎΠ±ΠΈΡ‚ΡŒ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ нСобходимости, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° микросСрвисы
  • β“ΠšΠ°ΠΊ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ баланс Π² IaC-Π΅? НапримСр Π΅ΡΡ‚ΡŒ Π₯ ΠΊΠΎΠΌΠ°Π½Π΄, для ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΠ½Ρ„Ρ€Ρƒ: ΡΠ΅Ρ‚ΡŒ, сСрвСра
    • для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π² ΠΎΠ΄Π½ΠΎΠΌ tf ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ ΠΌΠ΅Π½Π΅Π΄ΠΆΠΈΡ‚ΡŒ ΠΈ ΡΠ΅Ρ‚ΡŒ, ΠΈ сСрвСра
    • Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ сСтями для всСх ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ мСста
    • Ссли Ρƒ нас Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒΡΡ Π΅Ρ‰Π΅ ΠΊΡƒΡ‡Π° рСсурсов, Ρ‚ΠΈΠΏΠ° bd, s3, X, Ρ‚ΠΎ просто ΠΏΠΎΠ΄Ρ€ΠΎΠ±ΠΈΡ‚ΡŒ это слСгка Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°? tf-modules?

2. Dependencies (43) - (Dockerfile | .lock )

  • Никогда Π½Π΅ слСдуСт Ρ€Π°ΡΡΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ Π½Π° Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ вСрсии, всС внСшниС зависимости Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ТСстко Π·Π°ΠΏΠΈΠ½Π΅Π½Ρ‹ (я Π΄ΡƒΠΌΠ°ΡŽ слСдуСт Π΄ΠΎΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π»Π΅Π³ΠΊΠΈΠΉ флСкс Ρ‡Π΅Ρ€Π΅Π· version-constraints, Ρ‚ΠΈΠΏΠ° 0.1.X, Π½ΠΎ это риск)

3. Config (71) - (env)

  • ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния (Π½ΠΎ я Π±Ρ‹ сказал, Ρ‡Ρ‚ΠΎ это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΎΡ‡ ΠΌΠ΅Π»ΠΊΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ годится, Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ флСкса - traefik, ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ Π² config.toml, env_vars, Π° Ρ‚Π°ΠΊ ΠΆΠ΅ Ρ„Π»Π°Π³ΠΈ ΠΏΡ€ΠΈ запускС - Ρƒ всСго это Ρ‡ΡƒΡ‚ΡŒ-Ρ‡ΡƒΡ‚ΡŒ Ρ€Π°Π·Π½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚)
  • ❓ Если Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΎΠ± ΠΈΠ½Ρ„Ρ€Π΅, Ρ‚ΠΎ ΠΊΠ°ΠΊ Ρ‚ΡƒΡ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ баланс Ρ‚Π΅ΠΌΠΏΠ»Π΅ΠΉΡ‚ΠΎΠ² ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Π΄Π°ΡŽΡ‚ΡΡ Π² Ρ‚Π΅ΠΌΠΏΠ»Π΅ΠΉΡ‚Ρ‹?

4. Backing Services (67) - (DB | cache)

  • Backing сСрвисы (Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ сообщСний ΠΈ Ρ‚.Π΄.) Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΊΠ°ΠΊ присоСдиняСмыС рСсурсы.
  • ❓ - являСтся Π»ΠΈ PVC Ρ‚Π°ΠΊΠΈΠΌ сСрвисом? 🀣
  • ❓ - Ссли ΠΌΡ‹ Π² infra-e, Ρ‚ΠΎ для нас Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠΌ являСтся helm chart, Π° ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΈΡ… Π±ΡƒΠ΄Π΅ΠΌ Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π½Π΅ Ρ‚Π°ΠΊ Π²Π°ΠΆΠ½ΠΎ? (helm install / argocd / flux ) - Π·Π²ΡƒΡ‡ΠΈΡ‚ ΠΎΡ‡ натянуто πŸ˜‰

5. Build, release, run (77) - (DevOps | CI/CD/CD -> SRE)

  • Π”ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ:
    • сборкой Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Π°
    • Ρ€Π΅Π»ΠΈΠ·ΠΎΠΌ (доставка + Π΄Π΅ΠΏΠ»ΠΎΠΉΠΌΠ΅Π½Ρ‚ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ CD/CD)
    • ΠΎΠΏΠ΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ

6. Processes (57) - (SIGTERM | SIGKILL)

  • ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ стСйтлСсс, быстро ΡƒΠ±ΠΈΠ²Π°Ρ‚ΡŒΡΡ, ΠΈ Π±Ρ‹Ρ‚ΡŒ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄Ρ‹ Π²Ρ‹Ρ…ΠΎΠ΄Π° ΠΎΡ‚ CRI, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ Π² ΠΎΠ±Π»Π°Ρ‡Π½ΠΎΠΉ срСдС

7. Port Binding (85) - (port-mapping)

  • ΠΌΠ°Π»ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΠΎ Π² ΠΊΡƒΠ±Π΅Ρ€Π΅, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ слСдуСт ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎΡ€Ρ‚ ΠΊΠ°ΠΊ ENV, Π½Π° случай Ссли ΠΌΡ‹ Π·Π°Π΄ΡƒΠΌΠ°Π΅ΠΌ Π·Π°ΠΏΠΈΡ…Π°Ρ‚ΡŒ всС прилоТСния Π² ΠΎΠ΄ΠΈΠ½ Pod / docker-compose service?

8. Concurrency (55) - (HPA)

  • ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡƒΠΌΠ΅Ρ‚ΡŒ Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΡŒΠ½ΠΎ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ, поэтому Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ стСйтлСсс

9. Disposability (90) - (GC)

  • ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ быстро ΠΏΠΎΠ΄Π½ΠΈΠΌΠ°Ρ‚ΡŒΡΡ ΠΈ быстро ΡƒΠ±ΠΈΠ²Π°Ρ‚ΡŒΡΡ

10. Dev/prod parity (95) - (tools | CI/CD)

  • dev ΠΈ prod ΠΏΠΎ Ρ‚ΡƒΠ»Π°ΠΌ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΡ…ΠΎΠΆΠΈΠΌ для Ρ€Π°Π·Ρ€Π°Π±Π°

11. Logs (101)

  • Π›ΠΎΠ³ΠΈ ΠΏΠΈΡˆΡƒΡ‚ΡΡ Π² stdout ΠΈ коллСктятся Π°Π³Π΅Π½Ρ‚ΠΎΠΌ, ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π² json

12. Admin Processes (107) - (declarative)

  • АдминскиС таски Ρ‚ΠΈΠΏΠ° ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ Π‘Π”, Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ, IaC

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: fastapi-12-factor

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π½Π° основС конспСкт ΠΎΡ‚ KK

Код - https://github.com/karma-git/fastapi-12-factor

1. Codebase

Бписок ΠΈ содСрТимоС Ρ„Π°ΠΉΠ»ΠΎΠ²

APP_LOGLEVEL = WARNING
UVICORN_PORT = 8080
REDIS_HOST = redis-db
REDIS_PORT = 6379
---

version: '3'

services:
  api:
    container_name: "fastapi-12f"
    image: karmawow/fastapi-12f:latest
    build:
      context: ./
      dockerfile: Dockerfile
    volumes:
      - ./:/home/app
    env_file:
      - .env
    restart: always
    ports:
      # machine:container
      - "8000:8080"

  redis-db:
    image: redis
    container_name: redis
    command: redis-server /usr/local/etc/redis/redis.conf
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
      - ./redis.conf:/usr/local/etc/redis/redis.conf
FROM python:3.10.0-alpine3.14

COPY ./requirements.txt ./requirements.txt

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

RUN addgroup --gid 10001 app \
  && adduser \
    --uid 10001 \
    --home /home/app \
    --shell /bin/ash \
    --ingroup app \
    --disabled-password \
    app

WORKDIR /home/app

USER app

COPY ./ /home/app

# default, can be overrided
ENV UVICORN_PORT 8000
EXPOSE 8000

ENTRYPOINT ["/usr/local/bin/uvicorn"]
CMD ["main:app", "--reload", "--host=0.0.0.0",  "--no-access-log"]
import os
import logging

from fastapi import FastAPI
from pydantic import BaseSettings
import redis

import json_log_formatter


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    app_log_level: str = os.environ.get('APP_LOGLEVEL', 'INFO').upper()
    port: int = os.environ.get("UVICORN_PORT", 8000)
    redis_host: str = os.environ.get("REDIS_HOST", "redis-db")
    redis_port: int = os.environ.get("REDIS_PORT", 6380)

settings = Settings()

logger = logging.getLogger(__name__)
stdout = logging.StreamHandler()
stdout.setLevel(level=settings.app_log_level)
formatter = json_log_formatter.VerboseJSONFormatter()
stdout.setFormatter(formatter)
logger.addHandler(stdout)

app = FastAPI()
redis_db = redis.Redis(host=settings.redis_host, port=settings.redis_port)

@app.get("/")
async def welcomeToKodeKloud():
    try:
      redis_db.incr('visitorCount')
      visitCount = str(redis_db.get('visitorCount'), 'utf-8')
    except redis.exceptions.ConnectionError as e:
        logger.critical(e)
        return {"message": "Welcome to KODEKLOUD!"}
    else:
        logger.debug(visitCount)
        return {"message": "Welcome to KODEKLOUD!", "request_count": visitCount}

@app.get("/info")
async def info():
    return {
        "app_name": settings.app_name,
        "app_log_level": settings.app_log_level,
        "app_port": settings.port,
        "redis_host": settings.redis_host,
        "redis_port": settings.redis_port,
    }
# pip install fastapi uvicorn
# pip freeze | tee requirement.txt
anyio==3.6.2
click==8.1.3
fastapi==0.95.0
h11==0.14.0
idna==3.4
pydantic==1.10.7
sniffio==1.3.0
starlette==0.26.1
typing_extensions==4.5.0
uvicorn==0.21.1
async-timeout==4.0.2
redis==4.5.4
JSON-log-formatter==0.5.2

2. Dependencies

Π₯Ρ€Π°Π½ΠΈΠΌ всС нСстандартныС python Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π² Ρ„Π°ΠΉΠ»Π΅, Π° само ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ собираСм Π² Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ Dockerfile:

# pip install fastapi uvicorn
# pip freeze | tee requirement.txt
anyio==3.6.2
...
...

# ΠšΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ Ρ„Π°ΠΉΠ» с зависимостями
COPY ./requirements.txt ./requirements.txt

# УстанавливаСм зависимости
RUN pip install --no-cache-dir -r requirements.txt

...

3. Config; Backend; Port-Binding; Logs

# ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ стандартный ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ логирования
APP_LOGLEVEL = WARNING

# ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ стандартный ΠΏΠΎΡ€Ρ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡΠ»ΡƒΡˆΠ°Π΅Ρ‚ server
# ΠŸΡ€ΠΈ смСнС, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ со стороны Infrastructure Ρ‚Π°ΠΊΠΆΠ΅ Π΅Π³ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ
UVICORN_PORT = 8080

# ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ стандартный hostname redis
# ΠŸΡ€ΠΈ смСнС, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ со стороны Infrastructure Ρ‚Π°ΠΊΠΆΠ΅ Π΅Π³ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ
REDIS_HOST = redis-db

# ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ стандартный ΠΏΠΎΡ€Ρ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡΠ»ΡƒΡˆΠ°Π΅Ρ‚ redis
# ΠŸΡ€ΠΈ смСнС, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ со стороны Infrastructure Ρ‚Π°ΠΊΠΆΠ΅ Π΅Π³ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ
REDIS_PORT = 6379
...

# стандартный ΠΏΠΎΡ€Ρ‚ uvicorn
ENV UVICORN_PORT 8000
EXPOSE 8000

# Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π±ΠΎΠ»Π΅Π΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ uvicorn Π² main.py
# ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ python, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ с Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ argparse
# Π½ΠΎ со стороны infra ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ENTRYPOINT ΠΈ CMD
ENTRYPOINT ["/usr/local/bin/uvicorn"]
CMD ["main:app", "--reload", "--host=0.0.0.0",  "--no-access-log"]
---
...

services:
  api:
    ...
    # ΠΏΡ€ΠΎΠΊΠΈΠ΄Ρ‹Π²Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния ΠΈΠ· Ρ„Π°ΠΉΠ»Π° Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ
    env_file:
      - .env
    ports:
      # ΠΌΠ°ΠΏΠΈΠ½Π³ ΠΏΠΎΡ€Ρ‚ΠΎΠ²
      # docker-host:container, Π³Π΄Π΅ ΠΏΠΎΡ€Ρ‚ Π² container Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ с Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ UVICORN_PORT ΠΈΠ· env
      - "8000:8080"

  # Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ REDIS_HOST ΠΈΠ· env Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ
  redis-db:
    # docker-host:container, Π³Π΄Π΅ ΠΏΠΎΡ€Ρ‚ Π² container Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ с Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ REDIS_PORT ΠΈΠ· env
    ports:
      - "6379:6379"
import os
import logging

from fastapi import FastAPI
from pydantic import BaseSettings
import redis

import json_log_formatter

# Класс Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ ΠΈ сохранСния настроСк Ρ‡Π΅Ρ€Π΅Π· pydantic
class Settings(BaseSettings):
    app_name: str = "Awesome API"
    app_log_level: str = os.environ.get('APP_LOGLEVEL', 'INFO').upper()
    port: int = os.environ.get("UVICORN_PORT", 8000)
    redis_host: str = os.environ.get("REDIS_HOST", "redis-db")
    redis_port: int = os.environ.get("REDIS_PORT", 6380)

# ΠžΠ±ΡŠΠ΅ΠΊΡ‚ dict, с настройками
settings = Settings()

...

# Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
# ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π»ΠΎΠ³Π³Π΅Ρ€ ΠΈΠ· Ρ„Π°ΠΉΠ»Π°
logger = logging.getLogger(__name__)
# создаСм log хэндлСр
stdout = logging.StreamHandler()
# Π·Π°Π΄Π°Π΅ΠΌ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ логирования, TODO: Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ
stdout.setLevel(level=settings.app_log_level)
# создаСм json Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρ‚Π΅Ρ€
formatter = json_log_formatter.VerboseJSONFormatter()
# добавляСм Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρ‚Π΅Ρ€ ΠΊ хэндлСру
stdout.setFormatter(formatter)
# вСшаСм хэндлСр Π½Π° Π»ΠΎΠ³Π³Π΅Ρ€
logger.addHandler(stdout)

# ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΊ redis с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ ΠΈΠ· настроСк
redis_db = redis.Redis(host=settings.redis_host, port=settings.redis_port)

@app.get("/")
async def welcomeToKodeKloud():
    try:
      redis_db.incr('visitorCount')
      visitCount = str(redis_db.get('visitorCount'), 'utf-8')
    # ΠžΡ‚Π»Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ошибки ΠΈΠ½Ρ„Ρ€Ρ‹ ΠΈ Π»ΠΎΠ³ΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΡ…
    except redis.exceptions.ConnectionError as e:
        logger.critical(e)
        return {"message": "Welcome to KODEKLOUD!"}
    else:
        logger.debug(visitCount)
        return {"message": "Welcome to KODEKLOUD!", "request_count": visitCount}

Comments