discourse_docker의 얕은 git fetch 회귀 문제

안녕하세요,

docker_discourse의 최근 커밋으로 인해 app.yml의 version: 값에 태그(예: v2.6.0)를 지정하는 기능이 깨졌습니다. 이 기능은 구버전 discourse를 설치하는 데 유용하며, 테스트 목적으로 자주 사용됩니다.

version: v2.6.0을 지정하고 e2eb085714dfcf2aa0117b0f2fdf39b762b0e18d 커밋을 사용할 때 문제가 다음과 같이 나타납니다.

I, [2020-12-05T10:59:38.848743 #1]  INFO -- : > cd /var/www/discourse && git remote set-branches origin v2.6.0
I, [2020-12-05T10:59:38.852600 #1]  INFO -- : 
I, [2020-12-05T10:59:38.852639 #1]  INFO -- : > cd /var/www/discourse && git fetch --depth 1 origin v2.6.0
From https://github.com/discourse/discourse
 * tag                 v2.6.0     -> FETCH_HEAD
I, [2020-12-05T10:59:41.405163 #1]  INFO -- : 
I, [2020-12-05T10:59:41.405307 #1]  INFO -- : > cd /var/www/discourse && git checkout v2.6.0
error: pathspec 'v2.6.0' did not match any file(s) known to git
I, [2020-12-05T10:59:41.411796 #1]  INFO -- : 

이는 해당 커밋 바로 이전 커밋을 사용할 때 기대되는 출력과 다릅니다.

I, [2020-12-05T11:22:14.717910 #1]  INFO -- : > cd /var/www/discourse && git fetch origin v2.6.0
From https://github.com/discourse/discourse
 * tag                     v2.6.0     -> FETCH_HEAD
I, [2020-12-05T11:22:15.672616 #1]  INFO -- : 
I, [2020-12-05T11:22:15.672683 #1]  INFO -- : > cd /var/www/discourse && git checkout v2.6.0
Note: checking out 'v2.6.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at d6121249d3 Version bump to v2.6.0

이를 엄밀히 말해 버그라고 하지는 않겠지만, 더 복잡한 템플릿이나 다른 방법이 필요하더라도 구버전의 discourse를 설치하는 방법에 대한 일종의 안내를 제공하고자 합니다.

@Falco가 조사 중입니다.

깊이(depth)가 설정 가능해야 한다는 데 동의합니다. 기본값은 "shallow"로 하고, 환경 변수를 통해 간단히 설정할 수 있도록 하는 방식이 좋겠습니다.

여기서 문제는 체크아웃을 수행할 때 태그가 로컬에서 인식되지 않는 것 같습니다. 다음 (Discourse와 무관한) 이슈와 유사합니다:

https://stackoverflow.com/questions/35979642/what-is-git-tag-how-to-create-tags-how-to-checkout-git-remote-tags

git fetch --all을 실행하면 문제가 해결될 수 있지만, 사용하지 않는 참조가 나중에 다른 명령어로 정리되지 않는 한 이미지 크기가 얼마나 증가할지는 알 수 없습니다.

그럼에도 불구하고, git clone --depth 1 https://github.com/discourse/discourse.git --branch=$version이 문제를 해결할 것이라 생각합니다. --branch 옵션은 브랜치와 태그 모두를 허용하기 때문입니다. 다만 테스트를 해보지 않았고, 클론이 현재 master 브랜치를 사용해야 하는 이유가 있는지도 알 수 없습니다.

git clone --depth 1 https://github.com/discourse/discourse.git --branch=v2.6.0을 실행하면 전체 폴더 크기가 212MB이고, 그 안의 .git 폴더는 46MB입니다. 따라서 이 정도는 괜찮다고 생각합니다.

이렇게 하면 저장소 크기가 두 배가 됩니다 :slightly_frowning_face:

문제는 이미지 빌드 시점에 나중에 어떤 브랜치를 원할지 알 수 없다는 점입니다.

현재 설정은 이미지 크기를 줄이기 위해 변경되었으며, 이는 압축된 이미지 크기를 250MB(25%) 줄이는 큰 성과였습니다. stable, beta 또는 tests-passed와 같은 일반적인 브랜치를 사용할 때는 잘 작동합니다.

우회 방법으로, 태그로 전환하려면 app.yml 파일에 다음을 적용할 수 있습니다:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
+    - exec:
+        cd: $home
+        cmd:
+          - git fetch --depth=1 origin tag v2.5.0 --no-tags
+          - git checkout v2.5.0

또 다른 우회 방법은 app.yml의 최상위 레벨에 base_image 키를 추가하고 값으로 이전 버전의 base image를 지정하는 것입니다. 새로운 이미지가 이전 버전의 Discourse를 실행할 수 있도록 호환성을 유지하려는 시도를 하지 않기 때문에, 충분히 오래된 버전으로 돌아가는 경우 이것이 필요할 수 있습니다.

맞습니다. 그 시점에는 버전을 알 수 없으며, 기본 이미지가 현재 버전 + tests-passed 브랜치를 사용하는 것으로 보이지만, 해당 브랜치에는 이미지가 빌드되었을 당시의 커밋이 포함됩니다.

tests-passed 브랜치를 사용하더라도, 현재 방식은 리빌드가 더 느려지지 않을까요?

다음 지시문들을 고려해 보세요:

기본 이미지에서:

git clone --depth 1 https://github.com/discourse/discourse.git
cd discourse/
git remote set-branches --add origin tests-passed

web.template.yml에서

git reset --hard
git clean -f
git remote set-branches --add origin master
git pull
...
`git pull`이 호출되면 **전체 저장소가 가져와지며**, 이전에 얕은 클론(shallow clone)만 수행되었기 때문에 몇 분 정도 걸릴 수 있습니다. 로컬에서 위의 지시문만 실행해 보면 확인할 수 있습니다. 기본 이미지에 전체 저장소가 있는 것이 더 좋다고 주장하는 것은 아니지만, `web.template.yml`의 코드는 플러그인만 추가되었거나 `app.yml`의 설정만 변경된 경우에도 모든 리빌드 시마다 실행됩니다. 저는 (discourse가 아닌) 제 프로젝트에서 보통 새 버전마다 새 이미지를 생성하는 방식을 사용하지만, 이것이 여러분에게는 실현 가능하지 않을 수 있습니다(현재 여러분이 어떻게 처리하고 있는지 고려해 볼 때). 리빌드 시간이 증가하는 것을 느끼셨나요? (또는 대부분의 경우 전체 리빌드 시간에 비해 그 정도가 크지 않을 수도 있습니다)

업데이트

위의 단계를 다시 테스트해 보았는데 빠졌습니다. 처음 시도할 때 git 트리를 변경하는 다른 명령어를 실행한 것 같아서, git pull을 실행했을 때 모든 것을 가져오려고 시도했던 것으로 보입니다.

정말 그렇게 확실합니까?

➜  discoursesmall git:(6a42acbf) docker run --rm -it discourse/base:2.0.20201125-2246
root@b481d11669ba:/# cd /var/www/discourse/
root@b481d11669ba:/var/www/discourse# du -sh .                                                     
774M    . 
root@b481d11669ba:/var/www/discourse# git pull
...
root@b481d11669ba:/var/www/discourse# du -sh .                                                                
778M    . 

@lucasbasquerotto 말씀하신 대로 git pull은 엄밀히 말해 필수적이지 않다는 지적이 맞습니다. 다만, 여기에서 해당 부분을 제거했습니다.

이제 앞으로 discourse_docker와 다른 브랜치(또는 포크)가 조금 더 잘 호환될 수 있을 것입니다 :slight_smile:

네, fetch를 수행한 뒤 pull을 한 다음 올바른 브랜치에서 checkout을 하는 것을 확인했습니다. 따라서 git pull은 필요하지 않을 것 같습니다(다만 아직 테스트는 해보지 않았습니다).

태그의 경우 태그를 별도로 fetch해야 하는 것 같지만, 구현은 가능한 것으로 보입니다. 또한 브랜치가 태그보다 훨씬 더 자주 사용되므로, 태그는 사실상 엣지 케이스로 봐야 할 것 같습니다.

설정 파일 standalone.yml의 version 옵션이 효과가 없다고 가정해도 될까요?

여전히 효과가 있지만, 이제 브랜치에만 설정할 수 있습니다.

저도 같은 오류가 발생합니다. 저는 2.5.1 버전을 사용 중이었습니다.

이 작업을 수행한 후 다음과 같은 오류가 발생합니다:

I, [2020-12-31T11:50:24.701475 #1]  INFO -- : > cd /var/www/discourse && find /var/www/discourse ! -user discourse -exec chown discourse {} \+
chown: cannot dereference '/var/www/discourse/public/plugins/styleguide': No such file or directory

재빌드(rebuild)가 작동하지 않습니다. 도와주실 수 있나요?

언급된 키를 추가하고 discourse/base - Docker Image 에서 이전 버전의 이미지를 사용해보십시오.

이것은 실패하는 코드(버전을 가져올 수 없기 때문에 실패하는 코드)가 실행된 이후에 수행되므로 작동하지 않습니다. (web.template.yml 옆에 다음 내용을 담은 version.template.yml을 생성한 것이 작동했습니다:

params:
  home: /var/www/discourse

run:
  - exec:
      cd: $home
      hook: code
      cmd:
        - git fetch --tags

그리고 web.template.yml보다 앞서 이 파일을 containers/app.yml에 다음과 같이 포함시켰습니다:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/version.template.yml"
  - "templates/web.template.yml"

이것이 작동하려면 app.yml에서 version 최상위 키를 사용하지 말고, 오직 그 새로운 코드만 사용해야 합니다. 그렇게 하면 실패하지 않습니다.

확인해 주셔서 감사합니다. 제가 빠져 있던 부분이 바로 그 부분이었네요. 저처럼 혼란을 느끼고 계신 분들을 위해, discourse의 릴리스 태그를 가져오는 방법은 다음과 같습니다:

  • app.yml에서 version 매개변수가 설정되지 않았는지 확인합니다. 예를 들어:
    params:
      db_default_text_search_config: "pg_catalog.english"
      #  version: stable
    
  • app.yml의 끝부분 근처에 원하는 버전으로 체크아웃하는 코드를 추가합니다. 예를 들어:
    hooks:
      after_code:
        - exec:
            cd: $home/plugins
            cmd:
              - git clone https://github.com/discourse/docker_manager.git
    +    - exec:
    +        cd: $home
    +        cmd:
    +          - git fetch --depth=1 origin tag v2.5.0 --no-tags
    +          - git checkout v2.5.0
    

./launcher rebuild app을 실행하면 다음 일이 발생합니다:

  • 기본 version(즉, test_passed 브랜치)이 체크아웃됩니다.
  • v2.5.0 태그가 가져와져 체크아웃되며, 이는 사실상 이전 버전을 대체합니다.