내 Discourse가 다운되었어요. 인증서 문제일까요?

안녕하세요 @WesPenre :slight_smile:

에러는 스크린샷에 포함된 부분보다 더 위에 있을 가능성이 큽니다. 문제가 무엇인지 확인할 수 있도록 전체 로그를 여기에 붙여넣어 주시겠어요?

Discourse에 로그인할 수 없는 경우 오류 로그를 만드는 방법을 알려주실 수 있나요? WinSCP에서 찾을 수 있을까요? 그렇다면 로그의 디렉터리와 파일명은 무엇인가요?

이것이 맞나요? 이 파일이 런처 파일입니다:

#!/usr/bin/env bash

usage () {
  echo "사용법: launcher COMMAND CONFIG [--skip-prereqs] [--docker-args STRING]"
  echo "명령어:"
  echo "    start:       컨테이너 시작/초기화"
  echo "    stop:        실행 중인 컨테이너 중지"
  echo "    restart:     컨테이너 재시작"
  echo "    destroy:     컨테이너 중지 및 삭제"
  echo "    enter:       컨테이너 내부에서 명령어를 실행하기 위해 셸 열기"
  echo "    logs:        컨테이너의 Docker 로그 보기"
  echo "    bootstrap:   템플릿 기반 구성으로 컨테이너 부트스트랩"
  echo "    run:         마지막으로 부트스트랩된 이미지 컨텍스트에서 구성과 함께 주어진 명령어 실행"
  echo "    rebuild:     컨테이너 재빌드 (구 컨테이너 파괴, 부트스트랩, 새 컨테이너 시작)"
  echo "    cleanup:     24시간 이상 중지된 모든 컨테이너 삭제"
  echo "    start-cmd:   컨테이너 시작에 사용되는 docker 명령어 생성"
  echo
  echo "옵션:"
  echo "    --skip-prereqs             런처 선행 조건 검사 생략"
  echo "    --docker-args              docker 실행 시 전달할 추가 인자"
  echo "    --skip-mac-address         MAC 주소 할당하지 않음"
  echo "    --run-image                컨테이너 실행에 사용되는 이미지를 재정의"
  exit 1
}

# 나중에 재실행을 위해
SAVED_ARGV=("$@")

command=$1
config=$2

# user_args_argv는 인자 벡터가 파싱될 때 한 번만 할당됩니다.
user_args_argv=""
# user_args는 가변적입니다: 템플릿이 파싱될 때 그 값이 변경될 수 있습니다.
# user_args_argv의 부분 집합입니다.
user_args=""

user_run_image=""

if [[ $command == "run" ]]; then
  run_command=$3
fi

while [ ${#} -gt 0 ]; do
  case "${1}" in
  --debug)
    DEBUG="1"
    ;;
  --skip-prereqs)
    SKIP_PREREQS="1"
    ;;
  --skip-mac-address)
    SKIP_MAC_ADDRESS="1"
    ;;
  --docker-args)
    user_args_argv="$2"
    user_args="$user_args_argv"
    shift
    ;;
  --run-image)
    user_run_image="$2"
    shift
    ;;
  esac

  shift 1
done

if [ -z "$command" -o -z "$config" -a "$command" != "cleanup" ]; then
  usage
fi

# Docker는 대문자, 공백 또는 특수 문자를 허용하지 않으므로, 모든 것을 구축한 후에야 발견되는 것을 방지하기 위해 지금 잡아둡니다
re='[[:upper:]/ !@#$%^&*()+~`=]'
if [[ $config =~ $re ]];
  then
    echo
    echo "오류: 구성 이름 '$config'에는 대문자, 공백 또는 특수 문자를 포함할 수 없습니다. 올바른 구성 이름으로 수정하고 $0을 다시 실행하세요."
    echo
    exit 1
fi

cd "$(dirname "$0")"

pups_version='v1.0.3'
docker_min_version='17.03.1'
docker_rec_version='17.06.2'
git_min_version='1.8.0'
git_rec_version='1.8.0'
kernel_min_version='4.4.0'

config_file=containers/"$config".yml
cidbootstrap=cids/"$config"_bootstrap.cid
local_discourse=local_discourse
image="discourse/base:2.0.20230217-0055"
image_stable="discourse/base:2.0.20230116-0051"
docker_path=`which docker.io 2> /dev/null || which docker`
git_path=`which git`

if [ "${SUPERVISED}" = "true" ]; then
  restart_policy="--restart=no"
  attach_on_start="-a"
  attach_on_run="-a stdout -a stderr"
else
  attach_on_run="-d"
fi

if [ -n "$DOCKER_HOST" ]; then
  docker_ip=`sed -e 's/^tcp:\/\/\(.*\):.*$/\1/' <<< "$DOCKER_HOST"`
elif [ -x "$(which ip 2>/dev/null)" ]; then
  docker_ip=`ip addr show docker0 | \
                  grep 'inet ' | \
                  awk '{ split($2,a,"/"); print a[1] }';`
else
  docker_ip=`ifconfig | \
                  grep -B1 "inet addr" | \
                  awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
                  grep docker0 | \
                  awk -F: '{ print $3 }';`
fi

# https://stackoverflow.com/a/44660519/702738 에서 가져옴
compare_version() {
    if [[ $1 == $2 ]]; then
        return 1
    fi
    local IFS=.
    local i a=(${1%%[^0-9.]*}) b=(${2%%[^0-9.]*})
    local arem=${1#${1%%[^0-9.]*}} brem=${2#${2%%[^0-9.]*}}
    for ((i=0; i<${#a[@]} || i<${#b[@]}; i++)); do
        if ((10#${a[i]:-0} < 10#${b[i]:-0})); then
            return 1
        elif ((10#${a[i]:-0} > 10#${b[i]:-0})); then
            return 0
        fi
    done
    if [ "$arem" '<' "$brem" ]; then
        return 1
    elif [ "$arem" '>' "$brem" ]; then
        return 0
    fi
    return 1
}

fatal () {
  echo -e "\n$1\n"
  exit "${2:-1}"
}

install_docker() {
  echo "Docker가 설치되어 있지 않습니다. Launcher를 실행하려면 Docker를 설치해야 합니다."
  echo "https://docs.docker.com/installation/ 을 참조하세요"
  exit 1
}

pull_image() {
  # dockerhub TLS 오류를 우회하기 위해 단일 재시도 추가
  $docker_path pull $image || $docker_path pull $image
}

check_prereqs() {

  if [ -z $docker_path ]; then
    install_docker
  fi

  # 1. docker 데몬이 실행 중인가?
  # 경고는 신경 쓰지 않으므로 stderr를 /dev/null로 보냅니다.
  # 보통 swap에 대해 불평하는데 이는 중요하지 않습니다.
  test=`$docker_path info 2> /dev/null`
  if [[ $? -ne 0 ]] ; then
    echo "docker 데몬에 연결할 수 없습니다 - 실행 중인지 및 액세스 권한이 있는지 확인하세요"
    exit 1
  fi

  # 2. 승인된 스토리지 드라이버를 사용 중인가?
  if ! $docker_path info 2> /dev/null | egrep -q 'Storage Driver: (btrfs|aufs|zfs|overlay2)$'; then
    echo "Docker 설치에 지원되는 스토리지 드라이버가 사용되지 않고 있습니다. 계속 진행하면 설치에 문제가 발생할 수 있습니다."
    echo "overlay2가 권장되는 스토리지 드라이버이지만, zfs와 aufs도 작동할 수 있습니다."
    echo "기타 스토리지 드라이버는 문제가 있는 것으로 알려져 있습니다."
    echo "\"docker info\"를 실행하여 'Storage Driver' 줄을 확인하면 어떤 파일 시스템을 사용 중인지 알 수 있습니다."
    echo
    echo "기존의 지원되지 않는 스토리지 드라이버를 사용하여 계속 진행하려면,"
    echo "launcher 소스 코드를 읽고 이 검사를 우회하는 방법을 알아내야 합니다."
    exit 1
  fi

  # 3. 권장 docker 버전 사용 중인가
  test=($($docker_path --version))  # docker 버전 문자열 가져오기
  test=${test[2]//,/}  # 버전만 가져오고 쉼표가 있으면 제거

  # 최소 docker 버전 이상인지 확인
  if compare_version "${docker_min_version}" "${test}"; then
    echo "오류: Docker 버전 ${test}은(는) 지원되지 않습니다. 최소 ${docker_min_version}, 또는 권장 버전 ${docker_rec_version}으로(로) 업그레이드하세요"
    exit 1
  fi

  # 더 새로운 docker 버전 권장
  if compare_version "${docker_rec_version}" "${test}"; then
    echo "경고: Docker 버전 ${test}은(는) 비추천됩니다. ${docker_rec_version} 또는 더 새로운 버전으로 업그레이드하는 것을 권장합니다."
  fi

  arm=false
  case $(uname -m) in
    armv7l)
      echo "오류: 32비트 arm은 지원되지 않습니다. 하드웨어가 실험적으로 지원되는 arm64를 지원하는지 확인하세요."
      exit 1
      ;;
    aarch64 | arm64)
      echo "경고: aarch64에 대한 지원은 현재 실험 단계입니다. 문제가 있으면 https://meta.discourse.org/tag/arm 에서 보고해 주세요."
      image="discourse/base:aarch64"
      arm=true
      ;;
    x86_64)
      echo "x86_64 아키텍처 감지됨."
      ;;
    *)
      echo "오류: 알 수 없는 아키텍처 감지됨."
      exit 1
      ;;
  esac


  # 4. discourse docker 이미지가 다운로드되었는가
  test=`$docker_path images | awk '{print $1 ":" $2 }' | grep "$image"`

  # arm 실험적 지원은 고정 태그를 사용하므로 항상 pull
  if [ -z "$test" ] || [ $arm = true ]; then
    echo
    echo "경고: Discourse 기본 이미지를 다운로드하기 시작합니다"
    echo "이 과정은 네트워크 속도에 따라 몇 분에서 1시간까지 걸릴 수 있습니다"
    echo
    echo "인내심을 가져 주세요"
    echo

    pull_image
  fi

  # stable에는 구버전 이미지를 사용
  version=$(cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
      "require 'yaml'; puts YAML.load(STDIN.readlines.join)['params']['version']")
  if [ "$version" = "stable" ]; then
    image=$image_stable
    pull_image
  fi

  # 5. 권장 git 버전 사용 중인가
  test=($($git_path --version))  # git 버전 문자열 가져오기
  test=${test[2]//,/}  # 버전만 가져오고 쉼표가 있으면 제거

  # 최소 버전 이상인지 확인
  if compare_version "${git_min_version}" "${test}"; then
    echo "오류: Git 버전 ${test}은(는) 지원되지 않습니다. 최소 ${git_min_version}, 또는 권장 버전 ${git_rec_version}으로(로) 업그레이드하세요"
    exit 1
  fi

  # 최적 버전 권장
  if compare_version "${git_rec_version}" "${test}"; then
    echo "경고: Git 버전 ${test}은(는) 비추천됩니다. ${git_rec_version} 또는 더 새로운 버전으로 업그레이드하는 것을 권장합니다."
  fi

  # https://bugs.ruby-lang.org/issues/13885 로 인해 최소 커널 버전 확인
  test=($(uname -r))

  # 최소 버전 이상인지 확인
  if compare_version "${kernel_min_version}" "${test}"; then
    echo "오류: 커널 버전 ${test}은(는) 지원되지 않습니다. 최소 ${kernel_min_version}으로(로) 업그레이드하세요"
    exit 1
  fi

  # 6. stderr / out / tty에 연결 가능한가
  test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
  if [[ "$test" =~ "working" ]] ; then : ; else
    echo "Docker 설치가 올바르게 작동하지 않습니다"
    echo
    echo "참조: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
    exit 1
  fi

  # 7. docker 폴더에 부트스트랩을 위한 충분한 공간이 있는가
  folder=`$docker_path info --format '{{.DockerRootDir}}'`
  safe_folder=${folder:-/var/lib/docker}
  if [[ -d $safe_folder && $(stat -f --format="%a*%S" $safe_folder)/1024**3 -lt 5 ]] ; then
    echo "$safe_folder 이(가) 위치한 디스크에 5GB 미만의 여유 공간이 있습니다. 계속하려면 더 많은 공간이 필요합니다"
    df -h $safe_folder
    echo
    if tty >/dev/null; then
      read -p "시스템의 docker 이미지와 컨테이너를 정리하여 공간을 복구하려는 시도를 원하시나요? (y/N)" -n 1 -r
      echo
      if [[ $REPLY =~ ^[Yy]$ ]]
      then
        $docker_path container prune --force --filter until=24h >/dev/null
        $docker_path image prune --all --force --filter until=24h >/dev/null
        echo "정리가 성공적이었으면 이제 다시 시도해 볼 수 있습니다"
      fi
    fi
    exit 1
  fi

  # 8. 컨테이너 정의 파일에 액세스할 수 있으며 안전하지(모두가 읽을 수 있는) 않은가
  if [[ ! -e "$config_file" || ! -r "$config_file" ]]; then
    echo "오류: $config_file 이(가) 존재하지 않거나 읽을 수 없습니다."
    echo
    echo "사용 가능한 구성 ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
    exit 1
  elif [[ "$(find $config_file -perm -004)" ]]; then
    echo "경고: $config_file 파일은 모든 사람이 읽을 수 있습니다. 다음 명령을 실행하여 이 파일을 보호할 수 있습니다: chmod o-rwx $config_file"
  fi
}


if [ -z "$SKIP_PREREQS" ] && [ "$command" != "cleanup" ]; then
  check_prereqs
fi

set_volumes() {
  volumes=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
        "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
}

set_links() {
    links=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
        "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
}

find_templates() {
    local templates=`cat $1 | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
      "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`

    local arrTemplates=${templates// / }

    if [ ! -z "$templates" ]; then
      echo $templates
    else
      echo ""
    fi
}

set_template_info() {
    templates=$(find_templates $config_file)

    arrTemplates=(${templates// / })
    config_data=$(cat $config_file)

    input="hack: true"

    for template in "${arrTemplates[@]}"
    do
      [ ! -z $template ] && {
        input="$input _FILE_SEPERATOR_ $(cat $template)"
      }
    done

    # 항상 구성 파일을 마지막에 배치하여 우선순위가 있도록 합니다.
    input="$input _FILE_SEPERATOR_ $config_data"

    read -r -d '' env_ruby << 'RUBY'
    require 'yaml'

    input=STDIN.readlines.join
    # 데이터베이스를 위해 기본값으로 UTF-8 사용
    env = {'LANG' => 'en_US.UTF-8'}
    input.split('_FILE_SEPERATOR_').each do |yml|
       yml.strip!
       begin
         env.merge!(YAML.load(yml)['env'] || {})
       rescue Psych::SyntaxError => e
        puts e
        puts "*ERROR."
       rescue => e
        puts yml
        p e
       end
    end
    env.each{|k,v| puts "*ERROR." if v.is_a?(Hash)}
    puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
RUBY

    tmp_input_file=$(mktemp)

    echo "$input" > "$tmp_input_file"
    raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`

    rm -f "$tmp_input_file"

    env=()
    ok=1
    while read i; do
      if [ "$i" == "*ERROR." ]; then
        ok=0
      elif [ -n "$i" ]; then
        env[${#env[@]}]="${i//\{\{config\}\}/${config}}"
      fi
    done <<< "$raw"

    if [ "$ok" -ne 1 ]; then
      echo "${env[@]}"
      echo "YAML 구문 오류. containers/*.yml 구성 파일을 확인해 주세요."
      exit 1
    fi

    # 라벨
    read -r -d '' labels_ruby << 'RUBY'
    require 'yaml'

    input=STDIN.readlines.join
    labels = {}
    input.split('_FILE_SEPERATOR_').each do |yml|
       yml.strip!
       begin
         labels.merge!(YAML.load(yml)['labels'] || {})
       rescue Psych::SyntaxError => e
        puts e
        puts "*ERROR."
       rescue => e
        puts yml
        p e
       end
    end
    puts labels.map{|k,v| "-l\n#{k}=#{v}" }.join("\n")
RUBY

    tmp_input_file=$(mktemp)

    echo "$input" > "$tmp_input_file"
    raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$labels_ruby"`

    rm -f "$tmp_input_file"

    labels=()
    ok=1
    while read i; do
      if [ "$i" == "*ERROR." ]; then
        ok=0
      elif [ -n "$i" ]; then
        labels[${#labels[@]}]=$(echo $i | sed s/{{config}}/${config}/g)
      fi
    done <<< "$raw"

    if [ "$ok" -ne 1 ]; then
      echo "${labels[@]}"
      echo "YAML 구문 오류. containers/*.yml 구성 파일을 확인해 주세요."
      exit 1
    fi

    # 노출
    read -r -d '' ports_ruby << 'RUBY'
    require 'yaml'

    input=STDIN.readlines.join
    ports = []
    input.split('_FILE_SEPERATOR_').each do |yml|
       yml.strip!
       begin
         ports += (YAML.load(yml)['expose'] || [])
       rescue Psych::SyntaxError => e
        puts e
        puts "*ERROR."
       rescue => e
        puts yml
        p e
       end
    end
    puts ports.map { |p| p.to_s.include?(':') ? "-p\n#{p}" : "--expose\n#{p}" }.join("\n")
RUBY

    tmp_input_file=$(mktemp)

    echo "$input" > "$tmp_input_file"
    raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$ports_ruby"`

    rm -f "$tmp_input_file"

    ports=()
    ok=1
    while read i; do
      if [ "$i" == "*ERROR." ]; then
        ok=0
      elif [ -n "$i" ]; then
        ports[${#ports[@]}]=$i
      fi
    done <<< "$raw"

    if [ "$ok" -ne 1 ]; then
      echo "${ports[@]}"
      echo "YAML 구문 오류. containers/*.yml 구성 파일을 확인해 주세요."
      exit 1
    fi

   merge_user_args
}

if [ -z $docker_path ]; then
  install_docker
fi

[ "$command" == "cleanup" ] && {
  $docker_path container prune --filter until=1h
  $docker_path image prune --all --filter until=1h

  if [ -d /var/discourse/shared/standalone/postgres_data_old ]; then
    echo
    echo "$(du -hs /var/discourse/shared/standalone/postgres_data_old | awk '{print $1}') 공간을 차지하는 구버전 PostgreSQL 백업 데이터 클러스터 감지됨"
    read -p "삭제하시겠습니까? (y/N): " -n 1 -r && echo

    if [[ $REPLY =~ ^[Yy]$ ]]; then
      echo "/var/discourse/shared/standalone/postgres_data_old 에 있는 구버전 PostgreSQL 데이터 클러스터를 삭제하는 중..."
      rm -rf /var/discourse/shared/standalone/postgres_data_old*
    else
      exit 1
    fi
  fi

  exit 0
}

docker_version=($($docker_path --version))
docker_version=${test[2]//,/}
restart_policy=${restart_policy:---restart=always}

set_existing_container(){
  existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
}

run_stop() {

  set_existing_container

  if [ ! -z $existing ]
     then
       (
        set -x
        $docker_path stop -t 30 $config
       )
     else
       echo "$config 이(가) 시작되지 않았습니다!"
       echo "./discourse-doctor 이(가) 문제를 진단하는 데 도움이 될 수 있습니다."
       exit 1
  fi
}

set_run_image() {
  run_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['run_image']"`

  if [ -n "$user_run_image" ]; then
    run_image=$user_run_image
  elif [ -z "$run_image" ]; then
    run_image="$local_discourse/$config"
  fi
}

set_boot_command() {
  boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['boot_command']"`

  if [ -z "$boot_command" ]; then

    no_boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
      "require 'yaml'; puts YAML.load(STDIN.readlines.join)['no_boot_command']"`

    if [ -z "$no_boot_command" ]; then
      boot_command="/sbin/boot"
    fi
  fi
}

merge_user_args() {
  local docker_args

  docker_args=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
          "require 'yaml'; puts YAML.load(STDIN.readlines.join)['docker_args']"`

  if [[ -n "$docker_args" ]]; then
    user_args="$user_args_argv $docker_args"
  fi
}

run_start() {

   if [ -z "$START_CMD_ONLY" ]
   then
     existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
     echo $existing
     if [ ! -z $existing ]
     then
       echo "할 일이 없습니다. 컨테이너가 이미 시작되었습니다!"
       exit 0
     fi

     existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
     if [ ! -z $existing ]
     then
       echo "기존 컨테이너 시작 중"
       (
         set -x
         $docker_path start $config
       )
       exit 0
     fi
   fi

   set_template_info
   set_volumes
   set_links
   set_run_image
   set_boot_command

   # 컨테이너 구성에서 호스트 이름 및 설정 가져오기
   for envar in "${env[@]}"
   do
     if [[ $envar == DOCKER_USE_HOSTNAME* ]] || [[ $envar == DISCOURSE_HOSTNAME* ]]
     then
       # 환경 변수로 사용
       eval $envar
     fi
   done

   (
     hostname=`hostname -s`
     # 호스트 이름 재정의
     if [ "$DOCKER_USE_HOSTNAME" = "true" ]
     then
       hostname=$DISCOURSE_HOSTNAME
     else
       hostname=$hostname-$config
     fi

     # 허용된 문자열만 있도록 정규화해야 합니다. 이것은 더 포괄적이지만 먼저 bash가 어떻게 하는지 지켜보겠습니다.
     # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
     # docker는 더 많은 호스트 이름 규칙을 추가했습니다.
     hostname=${hostname//_/-}


     if [ -z "$SKIP_MAC_ADDRESS" ] ; then
      mac_address="--mac-address $($docker_path run $user_args -i --rm -a stdout -a stderr $image /bin/sh -c "echo $hostname | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'")"
     fi

     if [ ! -z "$START_CMD_ONLY" ] ; then
       docker_path="true"
     fi

     set -x

     $docker_path run --shm-size=512m $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
        -e DOCKER_HOST_IP="$docker_ip" --name $config -t "${ports[@]}" $volumes $mac_address $user_args \
        $run_image $boot_command

   )
   exit 0

}

run_run() {
  set_template_info
  set_volumes
  set_links
  set_run_image

  unset ERR
  (exec $docker_path run --rm --shm-size=512m $user_args $links "${env[@]}" -e DOCKER_HOST_IP="$docker_ip" -i -a stdin -a stdout -a stderr $volumes $run_image \
    /bin/bash -c "$run_command") || ERR=$?

  if [[ $ERR > 0 ]]; then
    exit 1
  fi
}

run_bootstrap() {
  set_template_info

  base_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`

  update_pups=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`

  if [[ ! X"" = X"$base_image" ]]; then
    image=$base_image
  fi

  # base_image가 항상 discourse/base인 것은 아니므로,
  # 항상 최신 버전에서 빌드하도록 보장합니다.
  pull_image

  set_volumes
  set_links

  if $docker_path run $user_args --rm -i $image gem which pups; then
    pups_command="/usr/local/bin/pups --stdin"
  else
    # 기본 이미지에 `pups`가 gem으로 설치되지 않았으면 git pull 방식으로 폴백
    pups_command="cd /pups &&"
    if [[ ! "false" =  $update_pups ]]; then
      pups_command="$pups_command git pull && git checkout $pups_version &&"
    fi
    pups_command="$pups_command /pups/bin/pups --stdin"
  fi

  echo $pups_command

  declare -i BOOTSTRAP_EXITCODE
  rm -f $cidbootstrap

  echo "$input" | $docker_path run --shm-size=512m $user_args $links "${env[@]}" -e DOCKER_HOST_IP="$docker_ip" --cidfile "$cidbootstrap" -i -a stdin -a stdout -a stderr $volumes $image \
    /bin/bash -c "$pups_command"
  BOOTSTRAP_EXITCODE=$?

  CONTAINER_ID=$(cat "$cidbootstrap")
  rm -f "$cidbootstrap"

  # 재시도를 나타내는 마법 종료 코드
  if [[ $BOOTSTRAP_EXITCODE -eq 77 ]]; then
    $docker_path rm "$CONTAINER_ID"
    exit 77
  elif [[ $BOOTSTRAP_EXITCODE -gt 0 ]]; then
    echo "부트스트랩이 종료 코드 $BOOTSTRAP_EXITCODE로 실패했습니다"
    echo "** 부트스트랩 실패 ** 이전의 오류 메시지를 찾아보세요. 하나 이상일 수 있습니다."
    echo "./discourse-doctor 이(가) 문제를 진단하는 데 도움이 될 수 있습니다."

    if [[ -n "$DEBUG" ]]; then
      if $docker_path commit "$CONTAINER_ID" $local_discourse/$config-debug; then
        echo "** 디버그 ** 진단을 위해 이미지 유지: $local_discourse/$config-debug"
      else
        echo "** 디버그 ** 진단을 위해 컨테이너 $CONTAINER_ID 커밋 실패"
      fi
    fi

    $docker_path rm "$CONTAINER_ID"
    exit 1
  fi

  sleep 5

  $docker_path commit \
    -c "LABEL org.opencontainers.image.created=\"$(TZ=UTC date -Iseconds)\"" \
    "$CONTAINER_ID" \
    $local_discourse/$config || fatal "$CONTAINER_ID 커밋 실패"
  $docker_path rm "$CONTAINER_ID"
}

case "$command" in
  bootstrap)
      run_bootstrap
      echo "부트스트랩 성공적으로 완료되었습니다. 시작하려면 ./launcher start $config 을(를) 사용하세요"
      exit 0
      ;;

  run)
      run_run
      exit 0
      ;;

  enter)
      exec $docker_path exec -it $config /bin/bash --login
      ;;

  stop)
      run_stop
      exit 0
      ;;

  logs)

      $docker_path logs $config
      exit 0
      ;;

  restart)
      run_stop
      run_start
      exit 0
      ;;

  start-cmd)
    START_CMD_ONLY="1"
    run_start
    exit 0;
    ;;

  start)
      run_start
      exit 0
      ;;

  rebuild)
      if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
        git branch -m master main
        git fetch origin
        git branch -u origin/main main
        git remote set-head origin -a
      fi

      if [ "$(git symbolic-ref --short HEAD)" == "main" ]; then
        echo "Launcher가 최신인지 확인 중"

        git remote update

        LOCAL=$(git rev-parse HEAD)
        REMOTE=$(git rev-parse @{u})
        BASE=$(git merge-base HEAD @{u})

        if [ $LOCAL = $REMOTE ]; then
          echo "Launcher가 최신 상태입니다"

        elif [ $LOCAL = $BASE ]; then
          echo "Launcher 업데이트 중..."
          git pull || (echo '업데이트 실패' && exit 1)

          echo "Launcher 업데이트 완료, 재시작 중..."
          exec "$0" "${SAVED_ARGV[@]}"

        elif [ $REMOTE = $BASE ]; then
          echo "사용자의 Launcher 버전이 origin보다 앞선 상태입니다"

        else
          echo "Launcher 소스가 분기되었습니다. 이는 개발 모드에서만 예상되는 사항입니다"
        fi

      fi

      set_existing_container

      if [ ! -z $existing ]
        then
          echo "구 컨테이너 중지 중"
          (
            set -x
            $docker_path stop -t 60 $config
          )
      fi

      run_bootstrap

      if [ ! -z $existing ]
        then
          echo "구 컨테이너 삭제 중"
          (
            set -x
            $docker_path rm $config
          )
      fi

      run_start
      exit 0
      ;;


  destroy)
      (set -x; $docker_path stop -t 10 $config && $docker_path rm $config) || (echo "$config 을(를) 찾을 수 없습니다" && exit 0)
      exit 0
      ;;
esac

usage

이 문제를 마무리하기 위해, PM의 도움으로 maxmind 관련 문제임이 드러났고, 해당 부분을 주석 처리하니 부트스트랩이 성공적으로 완료되었습니다. :+1: