Skip to content

Fly.io

Deploy App Servers Close to Your Users. Run your full stack apps (and databases!) all over the world. No ops required.

Categories

시작하기

flyctl 설치:

curl -L https://fly.io/install.sh | sh

가입 먼저 해야 한다면:

flyctl auth signup

가입된 아이디가 있다면:

fly auth login

앱 즉시 실행:

flyctl launch --image flyio/hellofly:latest

다음과 같은 질문 및 로그가 출력된다.

Creating app in /home/user/Project/cloud-api
Using image flyio/hellofly:latest
? Choose an app name (leave blank to generate one): cloud-api
? Select Organization: company (company)
Some regions require a paid plan (fra, maa).
See https://fly.io/plans to set up a plan.

? Choose a region for deployment: Tokyo, Japan (nrt)
Created app 'cloud-api' in organization 'company'
Admin URL: https://fly.io/apps/cloud-api
Hostname: cloud-api.fly.dev
? Would you like to set up a Postgresql database now? Yes
? Select configuration: Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk
Creating postgres cluster in organization company
Creating app...
Setting secrets on app cloud-api-db...
Provisioning 1 of 1 machines with image flyio/postgres-flex:15.2@sha256:8e00d751bb9811bc8511d7129db2cc5a515449cf4a7def8f1d60faacb2be91c6
Waiting for machine to start...
Machine 1781775c592389 is created
==> Monitoring health checks
  Waiting for 1781775c592389 to become healthy (started, 3/3)

Postgres cluster cloud-api-db created
  Username:    postgres
  Password:    q3IRDGIrX2RnLvk
  Hostname:    cloud-api-db.internal
  Flycast:     fdaa:1:a90f:0:1::2
  Proxy port:  5432
  Postgres port:  5433
  Connection string: postgres://postgres:[email protected]:5432

Save your credentials in a secure place -- you won't be able to see them again!

Connect to postgres
Any app within the company organization can connect to this Postgres using the above connection string

Now that you've set up Postgres, here's what you need to understand: https://fly.io/docs/postgres/getting-started/what-you-should-know/
Checking for existing attachments
Registering attachment
Creating database
Creating user

Postgres cluster cloud-api-db is now attached to cloud-api
The following secret was added to cloud-api:
  DATABASE_URL=postgres://cloud_api:[email protected]:5432/cloud_api?sslmode=disable
Postgres cluster cloud-api-db is now attached to cloud-api
? Would you like to set up an Upstash Redis database now? Yes
? Select an Upstash Redis plan Free: 100 MB Max Data Size

Your Upstash Redis database cloud-api-redis is ready.
Apps in the company org can connect to at redis://default:[email protected]
If you have redis-cli installed, use fly redis connect to connect to your database.

Redis database cloud-api-redis is set on cloud-api as the REDIS_URL environment variable
Wrote config file fly.toml
? Would you like to deploy now? Yes
==> Building image
Searching for image 'flyio/hellofly:latest' remotely...
image found: img_z1nr0lpjz9v5q98w
==> Creating release
--> release v2 created

--> You can detach the terminal anytime without stopping the deployment
==> Monitoring deployment
Logs: https://fly.io/apps/cloud-api/monitoring

 1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing]
--> v0 deployed successfully

정상적으로 종료되면 자신의 도메인을 연결한다.

  • CNAME을 연결하거나
  • A Record (ipv4)를 연결 하거나 (ipv4가 Shared IP 라면 CNAME으로 연결하자) 1
  • AAAA Record (ipv6)를 연결. (가비아 지원 안해서 CNAME으로 연결함)

마지막으로 인증서를 연결한다:

flyctl certs create api.server.com

그럼 다음과 같이 등록중이라는 메시지가 출력된다.

Your certificate for api.server.com is being issued. Status is Awaiting certificates. Make sure to create another certificate for www.api.server.com when the current certificate is issued.

홈페이지의 대시보드로 들어간 다음 상태를 확인하고 나중에 접속하면 된다.

만들어진 fly.toml 파일은 다음과 같다.

# fly.toml file generated for cloud-api on 2023-03-16T19:23:55+09:00

app = "cloud-api"
kill_signal = "SIGINT"
kill_timeout = 5
primary_region = "nrt"
processes = []

[build]
  image = "flyio/hellofly:latest"

[env]

[experimental]
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

Dockerfile 배포

Dockerfile로 배포하고 싶다면 [build] 섹션을 다음과 같이 변경하면 된다:

# ...
[build]
  dockerfile = "Dockerfile"
# ...

그리고 다음 명령을 날린다.

fly deploy

얼추 다음과 같은 로그가 출력된다.

Update available 0.0.485 -> v0.0.492.
Run "flyctl version update" to upgrade.
==> Verifying app config
--> Verified app config
==> Building image
Remote builder fly-builder-cool-meadow-3970 ready
==> Creating build context
--> Creating build context done
==> Building image with Docker
--> docker host: 20.10.12 linux x86_64
Sending build context to Docker daemon  14.48kB
[+] Building 47.1s (12/12) FINISHED
 => [internal] load remote build context                                                                                                             0.0s
 => copy /context /                                                                                                                                  0.1s
 => [internal] load metadata for docker.io/library/python:3.11.2-slim                                                                                3.9s
 => [builder 1/5] FROM docker.io/library/python:3.11.2-slim@sha256:f73b68edac8d591bffe7801eb2c583efe0b1fa081943cf82c6b600450e531480                  2.5s
 => => resolve docker.io/library/python:3.11.2-slim@sha256:f73b68edac8d591bffe7801eb2c583efe0b1fa081943cf82c6b600450e531480                          0.0s
 => => sha256:161a52751dd68895c01350e44e9761e3965e4cef0f983bc5b6c57fd36d7e513c 1.37kB / 1.37kB                                                       0.0s
 => => sha256:1a5738045625f379eeb688d2d9d10b206fe477d3995b0bef9a14eae4e4db4679 7.92kB / 7.92kB                                                       0.0s
 => => sha256:3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0 31.41MB / 31.41MB                                                     0.4s
 => => sha256:57d9937f91c017aba99f0f612c832a63021706b0ebe3e2f1cf33c382135ad5fd 1.08MB / 1.08MB                                                       0.1s
 => => sha256:e4c83445263eca20457ce4f6f94097c83bbc920a2a692a47150f7736ecfe37e2 11.95MB / 11.95MB                                                     1.5s
 => => sha256:c90883e1a33d1036ec41cd2da850dc29f3e16ef012a002dc11903d9b4d8f4f87 233B / 233B                                                           1.5s
 => => sha256:89c4bc491d9d30a35c22f2628673a2e0b6b23d846fb15062e72a1f89bac03dfa 3.37MB / 3.37MB                                                       0.9s
 => => sha256:f73b68edac8d591bffe7801eb2c583efe0b1fa081943cf82c6b600450e531480 1.65kB / 1.65kB                                                       0.0s
 => => extracting sha256:3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0                                                            1.1s
 => => extracting sha256:57d9937f91c017aba99f0f612c832a63021706b0ebe3e2f1cf33c382135ad5fd                                                            0.1s
 => => extracting sha256:e4c83445263eca20457ce4f6f94097c83bbc920a2a692a47150f7736ecfe37e2                                                            0.4s
 => => extracting sha256:c90883e1a33d1036ec41cd2da850dc29f3e16ef012a002dc11903d9b4d8f4f87                                                            0.0s
 => => extracting sha256:89c4bc491d9d30a35c22f2628673a2e0b6b23d846fb15062e72a1f89bac03dfa                                                            0.2s
 => [builder 2/5] RUN apt-get update &&     apt-get install -y --no-install-recommends gcc                                                          10.9s
 => [stage-1 2/4] WORKDIR /app                                                                                                                       0.1s
 => [builder 3/5] WORKDIR /app                                                                                                                       0.0s
 => [builder 4/5] COPY . .                                                                                                                           0.0s
 => [builder 5/5] RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/.wheels -r requirements.txt &&     python setup.py bdist_wheel &&     cp   6.8s
 => [stage-1 3/4] COPY --from=builder /app/.wheels /app/.wheels                                                                                      0.0s
 => [stage-1 4/4] RUN pip install --no-cache /app/.wheels/* &&     rm -rf /app/.wheels &&     addgroup --gid 1001 --system app &&     adduser --no  21.3s
 => exporting to image                                                                                                                               1.5s
 => => exporting layers                                                                                                                              1.5s
 => => writing image sha256:415582ed073b6372f9774788b33e4f5fda6c8533baa05d213aefb8bd69f0d767                                                         0.0s
 => => naming to registry.fly.io/cloud-api:deployment-01GVQ0ZRK9HCKJ823C9E4ER24H                                                              0.0s
--> Building image done
==> Pushing image to fly
The push refers to repository [registry.fly.io/cloud-api]
c5f07ba36921: Pushed
a365250f8510: Pushed
104b65258e23: Pushed
c348a6e56a2f: Pushed
53be024e4476: Pushed
e92949a21056: Pushed
7d13900c8624: Pushed
650abce4b096: Pushed
deployment-01GVQ0ZRK9HCKJ823C9E4ER24H: digest: sha256:3053db2265d8635756acf528971adc9fa3eaedb405ba25a886cb8b40b80a49ff size: 2001
--> Pushing image done
image: registry.fly.io/cloud-api:deployment-01GVQ0ZRK9HCKJ823C9E4ER24H
image size: 300 MB
==> Creating release
--> release v1 created

--> You can detach the terminal anytime without stopping the deployment
==> Monitoring deployment
Logs: https://fly.io/apps/cloud-api/monitoring

 1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing]
--> v1 deployed successfully

Go 프로젝트를 EC2에서 Fly.io로 이관한 후기: 더 재미나고, 월 $9 절약

두 개의 사이드 프로젝트를 Amazon EC2 인스턴스에서 호스팅하는 것에서 Fly.io를 사용하는 것으로 전환.

이를 통해 약 500줄의 Ansible 스크립트 및 구성 파일을 삭제할 수 있었고 한 달에 $9를 절약할 수 있었습니다.

  • 스태틱 파일을 CDN을 사용하다가 go:embed를 이용한 ETag 캐싱으로 변경
  • CRON을 간단한 백그라운드 goroutine으로, 설정파일 대신 환경변수 이용
  • 앱 아키텍처는 동일. Go net/http 서버와 SQLite DB를 그대로 이용
  • Go 웹 앱이 운영이 쉽다고 하지만, 개발자가 신경써야할 자잘한 설정들이 많이 필요함(Caddy 를 이용한 SSL 및 업그레이드 등)
    • 하지만 Fly.io로 하면 이런 일들이 필요없음
  • Fly.io 는 3개의 VM까지는 무료이고 그 이상은 VM당 월$2
    • 1 Shared CPU 와 256MB 램인데, Go 앱에게는 충분함

Connecting via WireGuard

See also

Favorite site

References