Yes
Whatever ENV you specify when you finally do you docker run on the image … will take.
Yes
Whatever ENV you specify when you finally do you docker run on the image … will take.
And doing those things at every boot of the container is reasonable?
Some people like this pattern, I do not, that is why rails introduces some super fancy locking around migrations to ensure they never run concurrently when a cluster of 20 app try to run migrations at the same time.
Some people just boot the same image and run the migrations in some out-of-band process.
But each container should still rake assets:precompile at least once?
Depends on how do you host those.
If you have a NFS share of some sort (like AWS EFS) or if you upload those to some object storage service that can only be done on bootstrap.
유용한 답변을 주신 모든 분들께 감사드립니다. 이 작업을 올바르게 수행하는 방법에 대해 몇 가지 더 질문이 있습니다.
컨테이너 빌드에 필요한 정보만 포함하는 부트스트랩용 최소한의 app.yaml을 준비하려고 합니다. 그 중 일부 정보는 명확하게 컨테이너 런타임용으로 intended된 것 같습니다. 예를 들어 볼륨 마운트나 포트 매핑 등이 그렇습니다. 하지만 환경 변수에 대해서는 확실하지 않습니다. 일단 시도해 보겠지만, 이 환경 변수들은 컨테이너 빌드 시(어떤 식으로든 Dockerfile에 주입되는 방식) 사용되는 것인가요, 아니면 컨테이너 런타임 시에만 사용되는 것인가요? 후자라면 해당 환경 변수가 적절한 k8s 구성 파일에 포함되도록 하겠습니다.
두 번째로, 여기 몇몇 분들이 이미지를 개인용 컨테이너 리포지토리에 푸시하는 방법에 대해 이야기했습니다. 이것이 필수인가요? 다시 말해, 빌드된 이미지에 Docker Hub 같은 공개 리포지토리에 공개되면 안 되는 기밀 정보가 포함되어 있나요? (아직 개인용 컨테이너 리포지토리가 없어서 하나를 설정하는 것을 피하고 싶습니다.)
마지막으로, 생성되는 컨테이너의 이름을 제어하는 app.yaml 설정이 있나요? 단순히 마무리 다듬기 차원의 질문이지만, 그렇게 할 수 있다면 좋겠습니다
.
도움 주시면 감사하겠습니다! (오래된 스레드를 다시 올리는 것이라 죄송합니다. Kubernetes에 Discourse를 설치하는 방법을 검색했을 때 Google에서 첫 번째로 나오는 결과가 이 스레드였습니다.)
@Geoffrey_Challen discourse 저장소와 플러그인을 사용하여 이미지를 생성하고, ruby gems 및 기타 의존성을 설치한 후 레지스트리(예: DockerHub)에 푸시할 수 있습니다. 이 저장소는 **환경에 무관(agnostic)**하며, 비공개 플러그인 등을 포함하지 않는 한 공개될 수 있습니다. 이 기본 이미지는 스테이징 및 프로덕션 환경에서, 그리고 동일한 플러그인을 사용하는 경우 다른 프로젝트에서도 사용할 수 있습니다.
다만, 최종 이미지를 생성하기 위해 에셋 사전 컴파일, 데이터베이스 마이그레이션 및 SSL 인증서 생성과 같은 단계는 대상 머신에서 실행해야 합니다.
정확히 어떻게 k8s 클러스터에 이를 포함해야 하는지는 잘 모르겠습니다. 저는 보수적인 접근 방식을 취하여 discourse 팀의 공식 가이드에 따라 진행하되, 2단계로 분리하여 사용하고 있습니다.
이 부분은 제가 정확히 이해하지 못하는 것 같습니다. 이 작업들은 필요할 때 컨테이너 내부에서 자동으로 이루어지지 않나요? 저는 이걸 클라우드에 배포한 뒤, 머신에 셸 접근 권한을 얻는 일이 전혀 없기를 희망합니다. Discourse Docker 컨테이너에 들어갈 일이 거의(혹은 전혀) 없는 것과 비슷한 방식으로요.
컨테이너를 명시적으로 입력할 필요는 없습니다. 즉, CI 파이프라인에서 생성된 사전 컴파일된 이미지를 그대로 사용할 수 없다는 뜻입니다. 데이터베이스가 위치한 대상 머신에서 실행되어야 하기 때문입니다. (이 과정은 자동화할 수 있지만, 저는 k8s에서는 그렇게 하지 않았습니다. 대신 Ansible로 구현했습니다.)
아, 알겠습니다. 저는 데이터베이스를 컨테이너에 포함시키기 위해 올인원(all-in-one) 템플릿을 사용하고 있습니다. 10~1000명의 학생으로 구성된 지원 클래스를 다루는 우리의 사용 사례에는 이것이 적합합니다. 적어도 제 클래스에서는 이 구성으로 올인원이 잘 작동했습니다. 따라서 데이터베이스는 컨테이너 내부에 있습니다.
하지만 어쨌든, 컨테이너가 부팅될 때 Discourse가 데이터베이스 마이그레이션이나 기타 설정 단계를 실행하지 않나요?
데이터베이스가 실제로 컨테이너 안에 있는 것이 확실합니까? 아니면 RDBMS(이 경우 PostgreSQL)를 말씀하시는 것입니까? 지원되는 설치 방식은 데이터베이스를 컨테이너 외부(예상된 대로)에 두고, 컨테이너 내부 볼륨을 외부(호스트)에 매핑합니다. 또한 컨테이너를 다시 빌드하면 컨테이너가 재생성되어 모든 데이터를 잃게 됩니다.
데이터베이스가 정말로 컨테이너 내부에 있다면, 공식 설치 기반의 업그레이드를 어떻게 수행할 수 있을지 정확히 알지 못합니다. launcher 스크립트는 다시 빌드할 때 컨테이너를 여러 번 생성하고 파괴하며(컨테이너가停止되면 데이터베이스를 포함한 모든 데이터를 잃게 되는) --rm 옵션으로 실행하는 것 같습니다.
재빌드 방식을 변경해 보지는 않았지만, 컨테이너를 재생성하지 않고 모든 것을 컨테이너 내부에서 실행하도록 변경할 수 있다고 가정하면, 컨테이너를 레지스트리에 푸시할 수 있어야 합니다(비밀정보가 포함되므로 반드시 비공개 레지스트리를 사용해야 합니다). 그럼에도 불구하고 여러 가지 이유(일부는 이전에 언급된 바 있음)로 이 접근 방식을 권장하지 않습니다.
표준 설치에는 컨테이너 내부에 nginx, rails, postgres, redis가 포함되어 있습니다. postgres와 redis 데이터에는 외부 볼륨을 사용하며, 재빌드/업그레이드 시에도 삭제되지 않습니다.
네, 데이터베이스가 컨테이너 안에 있다고 한 부분이 좀 이상해서요. 표준 설치 방식이 변경되었거나, 데이터베이스 자체보다는 postgres를 의미하는 것이 아니라면요.
아니요 - 마이그레이션 및 에셋 컴파일 단계는 플러그인이 해결된 후 ./launcher bootstrap 단계에서 수행됩니다. 이 작업이 완료되면 컨테이너를 필요한 만큼 재시작하거나, 웹 프로세스를 여러 대의 머신에 분산 배치하는 등의 작업을 수행할 수 있습니다.
Imagineering, 설정은 다음과 같은 형태여야 합니다:
./launcher bootstrap를 실행하는 Job을 실행하고, 결과 이미지를 타임스탬프 기반 레이블(예: latest 대신)로 이름 변경하여 프라이빗 레지스트리에 푸시한 후, 배포를 해당 새 레이블로 롤아웃합니다(여기서는 local_discourse가 좋은 이름이 아닙니다).
Postgres는 컨테이너 안에서 실행됩니다. 표준 설치 템플릿을 사용하면 데이터는 컨테이너 외부에 저장되지만, Postgres 자체는 컨테이너 안에서 실행됩니다. Redis도 마찬가지입니다. 제가 "데이터베이스가 컨테이너 안에서 실행된다"고 말할 때, 데이터베이스 파일이 컨테이너 외부에 있더라도 데이터베이스 서버를 가리키는 것입니다. (다만 데이터베이스 파일은 "실행"되지 않으므로, 제 표현이 명확하다고 생각했지만—분명히 충분히 명확하지는 않더군요
.)
참고: 사실 Docker에 해당 디렉터리를 바운드 마운트하도록 구성하지 않는 한, 데이터가 반드시 컨테이너 외부에 저장되는 것도 아닙니다. 부트스트랩 과정에서 이 설정을 건너뛸 수 있었지만, 그 시점에는 컨테이너 재시작 시 데이터베이스 내용이 유지되지 않으므로 좋은 방법은 아닙니다.
장기적으로 링크된 대화(특히 docker-compose, 런처 스크립트 등에 관한 내용)를 읽은 후, 이제 이 내용이 나에게 더 명확하게 다가옵니다.
제가 하고 싶은 일은 다음과 같습니다:
./launcher bootstrap을 실행하여 postgres, redis 등 모든 종속성을 포함한 “fat”(포함형) Discourse 이미지를 생성합니다../launcher bootstrap을 다시 실행하여 이미지를 업데이트하고 데이터를 소실하지 않으면서 재배포합니다(물론이죠).제 이해로는, fat Discourse 이미지는 외부 서비스 종속성이 필요하지 않아야 합니다. 하지만 컨테이너 업그레이드 시 데이터가 유지되려면 postgres 데이터베이스 파일은 컨테이너 외부에 존재해야 합니다. 이는 괜찮습니다. 이를 위해 k8s 영구 볼륨(persistent volume)을 생성하면 되니까요.
여기서 제가 예상하는 유일한 문제가 있습니다. ./launcher bootstrap 동안 발생하는 대부분의 작업은 컨테이너 내부에 있는 파일만 건드립니다. 예를 들어, 에셋 사전 컴파일 같은 경우입니다. 이는 문제가 되지 않습니다. 그 결과물이 컨테이너 내부에 존재하며 업그레이드를 살아남을 필요가 없으니까요.
여기서 큰 예외는 데이터베이스 마이그레이션입니다. 이 단계는 부트스트랩이 완료된 _후_에 사용될 데이터베이스에 접근할 수 있어야 합니다. 따라서 저에게 이는 fat Discourse 이미지를 클라우드에 쉽게 배포하는 데 있어 가장 큰 장벽처럼 보입니다.
@sam 님이 여러 차례 고객에게 Discourse를 재배포할 때 위에서 설명한 것과 유사한 워크플로우를 사용한다고 언급한 것을 확인했습니다. 하지만 이 방식이 작동하는 이유는 그들의 Discourse 이미지가 클러스터에서 실행되는 데이터베이스 서버(그리고 아마도 Redis도)를 사용하도록 구성되어 있기 때문이라고 추측합니다. 이는 여러 배포를 지원하는 데 합리적인 선택이지만, 제가 원하는 것과 정확히 일치하지는 않습니다. 즉, 부트스트랩 프로세스가 프로덕션 데이터베이스를 수정할 수 있다는 뜻이거나, 데이터베이스 업그레이드와 마이그레이션이 외부에서 처리되므로 데이터베이스 마이그레이션 단계가 완전히 건너뛸 수도 있다는 뜻입니다. @sam 님: 확인해 주실 수 있을까요?
어쨌든, 제게는 이것이 ./launcher bootstrap 중에而不是 컨테이너 시작 시점에 데이터베이스 마이그레이션을 실행하는 방법을 찾아야 한다는 것을 의미합니다. 그 시점에서 이를 수행하는 한 가지 방법은 다음과 같습니다:
./launcher bootstrap을 사용하여 로컬에서 fat Discourse 컨테이너를 빌드하되, 나중에 사용되지 않을 것이므로 빈 로컬 데이터베이스를 가리키는 볼륨 마운트를 사용합니다. 이렇게 하면 컨테이너 내부의 모든 것이 올바르게 설정되지만, postgres 관련 작업만 완료되지 않습니다.멀티 사이트 구성에 관심이 있으실 수 있습니다.
두 가지 큰 문제에 직면해 있습니다. Discourse는 Kubernetes를 지원하지 않으므로 커스텀 코드가 필요합니다. 또한 Discourse 팀이 수익을 얻는 영역(대규모 수의 포럼 호스팅)에 근접하고 있으므로, 받을 수 있는 지원 수준이 떨어질 것입니다.
제 조언은? 클러스터 외부에서 VM으로 정적 스케줄링을 수행하여 멀티 사이트 구성을 실행하세요. (또는 동일한 Ingress를 유지하기 위해 VM을 가리키는 Service Type=ExternalName을 사용할 수 있습니다.)
음… 이 작업을 수행하는 한 가지 방법을 알아냈습니다. 100% 만족스럽지는 않지만, 작동은 합니다. 그리고 Postgres, Redis 등을 포함하는 단순한 단일 컨테이너 기반의 ‘fat’ Discourse 이미지를 Kubernetes에 배포하려는 다른 사람들에게도 유용할 수 있습니다.
부트스트랩 과정을 살펴본 결과, 불행히도 두 가지 서로 다른 유형의 작업이 섞여 있다는 것을 알게 되었습니다. 하나는 컨테이너 자체에만 영향을 미치는 작업이고, 다른 하나는 주로 postgres 데이터 파일이 저장된 /shared 볼륨 마운트를 통해 주변 환경으로 영향을 미치는 작업입니다. 이러한 단계들을 분리하려고 애쓰기보다는, 컨테이너가 실제로 배포될 환경에서 부트스트랩 단계를 실행하는 것이 더 합리적이라고 판단했습니다.
불행히도, launcher bootstrap은 컨테이너를 생성하고 Docker를 사용하려고 합니다. 따라서 다른 컨테이너 내부(예: 클라우드에서 실행 중인 컨테이너)에서 launcher를 실행하는 것은 Docker-in-Docker 설정을 복잡하게 다루는 것(가능은 하지만, 모범 사례로 여겨지지 않음)이거나, 하위 Docker 데몬을 노출하는 것을 의미합니다. 사실 두 번째 접근 방식이 작동할지조차 확신이 서지 않습니다. 왜냐하면 볼륨 마운트를 노드의 로컬 파일시스템에 대해 해석할 것 같지만, 우리의 시나리오에서는 /shared를 Kubernetes의 영구 볼륨에 마운트하기를 원하기 때문입니다. 아마 Docker-in-Docker 경로는 작동할 수 있지만, 그러면 중첩된 컨테이너 내부에서 외부 컨테이너로, 그리고 거기서 Kubernetes 영구 볼륨으로 이어지는 이상한 삼중 볼륨 마운트가 생길 것입니다. 그것은… 현명하지 않은 것처럼 들립니다.
그러나 본질적으로 launcher bootstrap은 app.yml의 templates 값을 처리하여 하나의 큰 .yml 파일을 생성한 후, 부트스트랩 과정이 끝나면 그것을 Discourse 베이스 이미지로 전달합니다. 따라서 설정 파일을 추출할 수 있다면, 어떤 기계에서든 설정을 생성할 수 있고, 클라우드에서 시작하는 컨테이너로 그것을 전달하는 방법만 찾으면 됩니다.
따라서 개요로, 우리가 따를 단계는 다음과 같습니다:
launcher를 사용하여 부트스트랩 설정 생성pups 사용)을 수행한 후 Discourse를 시작하도록 수정된 Discourse 베이스 이미지에 해당 설정 전달STDOUT에 병합된 설정을 기록하는 dump 명령을 지원하기 위해 launcher에 필요한 변경 사항은 다음과 같습니다:
run_dump() {
set_template_info
echo "$input"
}
(이 명령은 우리의 discourse_docker 포크에서 사용 가능합니다.)
따라서 첫 번째 단계는 위에서 추가한 새로운 launcher dump 명령을 사용하여 부트스트랩 설정을 만드는 것입니다:
# app 대신 컨테이너 구성 이름을 대체하세요
./launcher dump app > bootstrap.yml
다음으로, /sbin/boot를 통해 부팅하기 전에 컨테이너를 부트스트랩하기 위해 pups를 실행하도록 하는 컨테이너가 필요합니다. 저는 베이스 discourse 이미지에 작은 변경을 가하기 위해 다음 Dockerfile을 사용했습니다:
FROM discourse/base:2.0.20191219-2109
COPY scripts/bootstrap.sh /
CMD bash bootstrap.sh
여기서 scripts/bootstrap.sh는 다음 내용을 포함합니다:
cd /pups/ && /pups/bin/pups --stdin < /bootstrap/bootstrap.yml && /sbin/boot
저는 이것을 geoffreychallen:discourse_base:2.0.20191219-2109로 게시했습니다. (참고: 베이스 Discourse docker 이미지의 부팅 명령을 수정하여 같은 것을 달성할 수도 있지만, pups가 설정 파일을 읽도록 하는 데 필요한 셸 리디렉션과 함께 작동하도록 만드는 것이 어려웠습니다.)
이제 Kubernetes 구성이 필요합니다. 제 구성은 다음과 같습니다:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: kotlin-forum-pvc
namespace: ikp
spec:
storageClassName: rook-ceph-block
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 64Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kotlin-forum-deployment
namespace: ikp
spec:
replicas: 0
selector:
matchLabels:
app: kotlin-forum
template:
metadata:
labels:
app: kotlin-forum
spec:
volumes:
- name: kotlin-forum
persistentVolumeClaim:
claimName: kotlin-forum-pvc
- name: bootstrap
configMap:
name: kotlin-forum-bootstrap
containers:
- name: kotlin-forum
image: geoffreychallen/discourse_base:2.0.20191219-2109
imagePullPolicy: Always
volumeMounts:
- name: kotlin-forum
mountPath: /shared/
- name: bootstrap
mountPath: /bootstrap/
ports:
- containerPort: 80
env:
- name: TZ
value: "America/Chicago"
- name: LANG
value: en_US.UTF-8
- name: RAILS_ENV
value: production
- name: UNICORN_WORKERS
value: "3"
- name: UNICORN_SIDEKIQS
value: "1"
- name: RUBY_GLOBAL_METHOD_CACHE_SIZE
value: "131072"
- name: RUBY_GC_HEAP_GROWTH_MAX_SLOTS
value: "40000"
- name: RUBY_GC_HEAP_INIT_SLOTS
value: "400000"
- name: RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
value: "1.5"
- name: DISCOURSE_DB_SOCKET
value: /var/run/postgresql
- name: DISCOURSE_DEFAULT_LOCALE
value: en
- name: DISCOURSE_HOSTNAME
value: kotlin-forum.cs.illinois.edu
- name: DISCOURSE_DEVELOPER_EMAILS
value: challen@illinois.edu
- name: DISCOURSE_SMTP_ADDRESS
value: outbound-relays.techservices.illinois.edu
- name: DISCOURSE_SMTP_PORT
value: "25"
---
apiVersion: v1
kind: Service
metadata:
name: kotlin-forum
namespace: ikp
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
selector:
app: kotlin-forum
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
namespace: ikp
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: kotlin-forum-ingress
spec:
rules:
- host: kotlin-forum.cs.illinois.edu
http:
paths:
- backend:
serviceName: kotlin-forum
servicePort: 80
여러분의 구성은 다를 것입니다. HTTPS를 업스트림에서 종결하므로 Ingress 구성을 수정했다는 점에 유의하세요. 또한 저는 모든 것을 하나의 파일에 넣고, 반복하면서 작동하지 않는 부분을 삭제한 다음, 다음 kubectl create -f 실행 시 Kubernetes가 중복을 건너뛰도록 하는 방식을 선호합니다. 또한 배포가 구성되는 즉시 시작되지 않도록 replicas: 0으로 설정했다는 점도 유의하세요. 이는 마무리해야 할 추가 구성 사항이 하나 더 있기 때문입니다.
launcher start가 컨테이너로 전달하는 환경 변수 목록을 복사해 왔습니다. 이 중 모두 필요한지, 아니면 구성에 따라 다른 변수가 누락되었을지는 알 수 없습니다. 결과는 사용자마다 다를 수 있습니다(YMMV).
컨테이너로 들어오는 두 개의 볼륨 맵이 있다는 점에 유의하세요. 첫 번째는 포드 재시작 후에도 유지되는 영구 볼륨으로 구성된 postgres용입니다. 두 번째는 다음과 같이 생성된 구성 맵입니다:
kubectl create configmap kotlin-forum-bootstrap --from-file=bootstrap.yml=<path/to/bootstrap.yml>
여기서 kotlin-forum-bootstrap은 Kubernetes 구성과 일치해야 하고, path/to/bootstrap.yml은 위에서 launcher dump를 사용하여 생성한 bootstrap.yml 파일의 경로입니다.
configmap이 제자리에 놓이면, 배포를 1개의 리플리카로 확장하여 Discourse가 부팅되고 launcher bootstrap이 수행했을 것과 동일한 부트스트랩 과정을 실행하는 것을 볼 수 있어야 합니다. 이 과정은 몇 분 정도 걸립니다. 완료되면 Discourse 설치 프로그램이 부팅됩니다.
(적어도 당분간) 완전히 구성되도록 하는 과정에서 제가 겪은 몇 가지 추가 노트입니다:
X-Forwarded 헤더, 즉 X-Fowarded-For, X-Forwarded-Proto, X-Forwarded-Port를 모두 전달해야 합니다. 이를 하지 않으면 Google 로그인 및 아마도 다른 로그인 제공자를 사용할 때 이상한 인증 오류가 발생합니다.nginx Ingress 컨트롤러는 전역 구성 맵에서 use-forwarded-headers를 설정하여 헤더를 전달하도록 구성되어야 합니다. 이는 제가 꽤 오래 걸렸습니다. 왜냐하면 적어도 몇 번은 잘못된 구성 맵을 편집한 후, 구성 맵이 변경되면 Ingress 컨테이너가 재시작될 것이라고 기대했기 때문입니다. (그렇지 않았습니다.)배포된 설치 프로그램을 업데이트하려면, 새로운 bootstrap.yml 파일을 다시 생성하고, 구성 맵을 업데이트한 다음, 컨테이너를 재시작합니다(가장 쉬운 방법은 0으로 축소하고 다시 1개의 리플리카로 확장하는 것입니다).
이것은 컨테이너가 빌드되기 전에 부트스트랩이 수행되기 때문에 약간의 다운타임을 초래합니다. 하지만 구성을 업데이트하거나/및 베이스 이미지를 변경해야 하는 경우 이는 피할 수 없어 보입니다. launcher rebuild은 stop; bootstrap; start로 문서화되어 있으므로, launcher 스크립트를 사용하여 수행하더라도 부트스트랩 과정은 여전히 다운타임을 유발합니다.
이러한 fat 컨테이너 Discourse 배포 패턴은 launcher 스크립트가 (a) 오프라인으로 수행할 수 있고 컨테이너 내 파일에만 영향을 미치는 부트스트랩 단계와 (b) 데이터베이스나 컨테이너 외부의 다른 상태에 수정 또는 액세스가 필요한 부트스트랩 단계를 더 명확하게 분리한다면 훨씬 지원하기 쉬울 것입니다. 위에서 설명한 접근 방식은 다소 답답합니다. 왜냐하면 이전 배포가 실행 중인 상태에서 수행할 수 있는 JS 미닉스, 에셋 미니파잉 및 기타 작업들이 모두 보이지만, 데이터베이스 액세스 없이 수행할 수 없는 다른 작업들(데이터베이스 마이그레이션 등)과 너무 뒤섞여 있기 때문입니다. templates/postgres.yml의 단계만 수행하는 컨테이너를 만드는 것에 대해 잠시 생각했지만, 데이터베이스 마이그레이션이 웹 템플릿에서 수행되고 있다는 것을 알고, 플러그인까지 생각하다가 결국 포기했습니다
.
더 나은 분리가 이루어진다면, fat 컨테이너의 재배포는 다음과 같이 작동할 수 있습니다:
이것은 다운타임을 약간 줄일 것입니다. 그 이유만으로 노력할 가치가 있을지는 모르지만, 공유 데이터베이스 등을 포함하는 더 복잡한 배포 시나리오를 단순화할 수도 있다고 상상할 수 있습니다.
그 말이 더 일리 있습니다. 부트스트랩 단계를 2단계로 분리할 때 제가 취했던 방식이 바로 그것입니다. 1단계는 격리된 환경(예: CI 파이프라인)에서 실행되어 Discourse 저장소, gems, 플러그인이 설치된 베이스 이미지를 생성할 수 있습니다. 2단계는 DB 마이그레이션과 에셋 생성을 수행해야 하므로 대상 머신에서 실행되어야 합니다(또는 적어도 프로덕션 데이터베이스에 접근할 수 있어야 합니다). 참고로 이는 컨테이너가 시작될 때가 아니라 부트스트랩 과정에서 수행됩니다.
네, 그렇게 되면 정말 좋을 것입니다. 이미 이를 요청한 적이 있습니다만, 언제 이것이 이루어질지는 모르겠습니다.
에셋 프리컴파일 작업이 데이터베이스(예: 커스텀 CSS 등)에 접근해야 하므로 완전히 격리된 환경에서 구현하기는 어려울 것입니다. 하지만 데이터베이스에 의존하는 부분만 별도의 단계로 수행할 수 있다면, 데이터베이스에 의존하지 않는 다른 에셋은 별도로 프리컴파일할 수 있을 것입니다. 다만 기술적으로 이를 구현하는 것이 얼마나 실현 가능한지는 모르겠습니다.
제가 직접 설치한 Kubernetes 환경에서도 거의 그렇게 하고 있습니다. 데이터 컨테이너와 웹 컨테이너를 분리하지 않고(또는 다른 방식의 외부 Postgres와 Redis를 사용하지 않고) k8s를 사용하는 것이 어떻게, 그리고 왜 가능한지 상상하기 어렵습니다. (고객을 위해 진행한 설치에서는 GCP 리소스를 이를 위해 사용했습니다.)
또한, 진정한 제로 다운타임 업그레이드를 위해 이해해야 할 skip_post_migration_updates라는 환경 변수가 있습니다. 이 변수는 여기에서 설명되어 있습니다.