# GitLab instance # NOTE instance/software layout is inspired by gitlab omnibus # NOTE all services are interconnected via unix sockets - because of easier # security and performance reasons (unix has 2x less latency and more # throughput compared to tcp over loopback). [buildout] extends = {{ gitlab_parameters_cfg }} {{ monitor_template }} parts = directory publish-instance-info # gitlab-<prog> # ? mailroom {% set gitlab_progv = 'rails rake unicorn sidekiq unicorn-startup' .split() %} {% for prog in gitlab_progv %} gitlab-{{ prog }} {% endfor %} gitconfig gitlab-work gitlab-shell-work service-gitlab-workhorse service-unicorn service-sidekiq service-nginx service-postgresql service-redis promise-redis service-gitaly cron-service cron-entry-logrotate logrotate-entry-cron on-reinstantiate # std stuff for slapos instance eggs-directory = {{ eggs_directory }} develop-eggs-directory = {{ develop_eggs_directory }} offline = true ################################## # GitLab instance parameters # ################################## [instance-parameter] # std stuff to fetch slapos instance parameters recipe = slapos.cookbook:slapconfiguration computer= ${slap-connection:computer-id} partition=${slap-connection:partition-id} url = ${slap-connection:server-url} key = ${slap-connection:key-file} cert = ${slap-connection:cert-file} # autogenerated gitlab instance parameters <= gitlab-parameters # adjust/override some default settings: # automatically load all available CPUs configuration.unicorn_worker_processes = {{ multiprocessing.cpu_count() + 1 }} configuration.nginx_worker_processes = {{ multiprocessing.cpu_count() }} # gitlab non-native parameters configuration.icp_license = # for convenience [external-url] recipe = slapos.cookbook:urlparse url = ${instance-parameter:configuration.external_url} [backend-info] host = ${instance-parameter:ipv6-random} port = 7777 # whether to use http or https - determined by external url url = ${external-url:scheme}://[${:host}]:${:port} # current slapuserX user = {{ pwd.getpwuid(os.getuid())[0] }} [publish-instance-info] recipe = slapos.cookbook:publish backend_url = ${backend-info:url} ############################# # GitLab instance setup # ############################# # 1. directories [directory] recipe = slapos.cookbook:mkdirectory home = ${buildout:directory} bin = ${:home}/bin etc = ${:home}/etc var = ${:home}/var log = ${:var}/log run = ${:var}/run srv = ${:home}/srv # slapos startup/service/promise scripts live here: startup = ${:etc}/run service = ${:etc}/service promise.slow = ${:etc}/promise.slow # gitlab: etc/ log/ ... [gitlab-dir] recipe = slapos.cookbook:mkdirectory etc = ${directory:etc}/gitlab log = ${directory:log}/gitlab var = ${directory:var}/gitlab tmp = ${:var}/tmp uploads = ${:var}/uploads assets = ${:var}/assets shared = ${:var}/shared artifacts = ${:shared}/artifacts lfs-objects = ${:shared}/lfs-objects builds = ${:var}/builds backup = ${directory:var}/backup public = ${:var}/public pages = ${:shared}/pages [gitlab-repo-dir] recipe = slapos.cookbook:mkdirectory repositories = ${directory:var}/repositories # gitlab wants it to be drwxrws--- # FIXME setting such mode with :mkdirectory is not possible, because mkdir(2) # does & 0777 and also there is umask. So we workaround: [gitlab-repo-xdir] recipe = plone.recipe.command stop-on-error = yes repositories = ${gitlab-repo-dir:repositories} command = chmod 02770 ${:repositories} [gitlab] etc = ${gitlab-dir:etc} log = ${gitlab-dir:log} var = ${gitlab-dir:var} tmp = ${gitlab-dir:tmp} uploads = ${gitlab-dir:uploads} assets = ${gitlab-dir:assets} shared = ${gitlab-dir:shared} artifacts = ${gitlab-dir:artifacts} lfs-objects = ${gitlab-dir:lfs-objects} builds = ${gitlab-dir:builds} backup = ${gitlab-dir:backup} repositories = ${gitlab-repo-xdir:repositories} public = ${gitlab-dir:public} pages = ${gitlab-dir:shared}/pages # gitlab-shell: etc/ log/ gitlab_shell_secret ... [gitlab-shell-dir] recipe = slapos.cookbook:mkdirectory etc = ${directory:etc}/gitlab-shell log = ${directory:log}/gitlab-shell [gitlab-shell] etc = ${gitlab-shell-dir:etc} log = ${gitlab-shell-dir:log} secret = ${secrets:secrets}/gitlab_shell_secret hook = # place to keep all secrets [secrets] recipe = slapos.cookbook:mkdirectory secrets = ${directory:var}/secrets mode = 0700 [gitaly-dir] recipe = slapos.cookbook:mkdirectory gitaly = ${directory:var}/gitaly sockets = ${:gitaly}/sockets internal = ${:sockets}/internal log = ${directory:log}/gitaly [gitaly] socket = ${gitaly-dir:sockets}/gitaly.socket log = ${gitaly-dir:log} location = {{ gitaly_location }} pid = ${directory:run}/gitaly.pid internal_socket = ${gitaly-dir:internal} # 2. configuration files [etc-template] recipe = slapos.recipe.template:jinja2 extensions = jinja2.ext.do mode = 0640 import-list = rawfile macrolib.cfg.in {{ macrolib_cfg_in }} context = raw autogenerated # This file was autogenerated. (DO NOT EDIT - changes will be lost) section instance_parameter instance-parameter section backend_info backend-info import urlparse urlparse raw git {{ git }} ${:context-extra} context-extra = [gitlab-etc-template] <= etc-template rendered= ${gitlab:etc}/${:_buildout_section_name_} [nginx-etc-template] <= etc-template rendered= ${nginx:etc}/${:_buildout_section_name_} [database.yml] <= gitlab-etc-template template= {{ database_yml_in }} context-extra = section pgsql service-postgresql [gitconfig] <= etc-template template= {{ gitconfig_in }} # NOTE put directly into $HOME/ - this way git will pick it up rendered= ${directory:home}/.${:_buildout_section_name_} [gitlab-shell-config.yml] <= etc-template template= {{ gitlab_shell_config_yml_in }} rendered= ${gitlab-shell:etc}/config.yml context-extra = import urllib urllib section gitlab gitlab section gitlab_shell gitlab-shell section gitlab_shell_work gitlab-shell-work section unicorn unicorn section service_redis service-redis raw redis_binprefix {{ redis_binprefix }} [gitlab.yml] <= gitlab-etc-template template= {{ gitlab_yml_in }} context-extra = import urllib urllib section gitlab gitlab section gitlab_shell gitlab-shell section gitlab_shell_work gitlab-shell-work section gitaly gitaly [nginx.conf] <= nginx-etc-template template= {{ nginx_conf_in }} context-extra = section directory directory section gitlab_workhorse gitlab-workhorse raw nginx_mime_types {{ nginx_mime_types }} raw nginx_gitlab_http_conf ${nginx-gitlab-http.conf:rendered} [nginx-gitlab-http.conf] <= nginx-etc-template template= {{ nginx_gitlab_http_conf_in }} context-extra = section nginx nginx section gitlab_work gitlab-work section gitlab_workhorse gitlab-workhorse [gitaly-config.toml] <= etc-template template= {{ gitaly_config_toml_in }} rendered= ${directory:etc}/${:_buildout_section_name_} context-extra = import urllib urllib section gitlab gitlab section gitlab_shell gitlab-shell section gitlab_shell_work gitlab-shell-work section gitaly gitaly [rack_attack.rb] <= gitlab-etc-template template = {{ rack_attack_rb_in }} [resque.yml] <= gitlab-etc-template template= {{ resque_yml_in }} context-extra = section redis service-redis [smtp_settings.rb] <= gitlab-etc-template template= {{ smtp_settings_rb_in }} # contains smtp password mode = 0600 [unicorn.rb] <= gitlab-etc-template template = {{ unicorn_rb_in }} context-extra = section unicorn unicorn section directory directory section gitlab_work gitlab-work # 3. bin/ # gitlab-<prog> [gitlab-bin] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:bin}/${:_buildout_section_name_} # NOTE $HOME needed to pick gitconfig environment = PATH = {{ node_bin_location }}:{{ gopath_bin }}:{{ yarn_location }}/bin:/usr/local/bin:/usr/bin:/bin BUNDLE_GEMFILE = {{ gitlab_repository_location }}/Gemfile HOME = ${directory:home} RAILS_ENV = production SIDEKIQ_MEMORY_KILLER_MAX_RSS = ${instance-parameter:configuration.sidekiq_memory_killer_max_rss} command-line = {{ bundler_4gitlab }} exec sh -c 'cd ${gitlab-work:location} && ${:prog} "$@"' ${:prog} {% for prog in gitlab_progv %} [gitlab-{{ prog }}] <= gitlab-bin prog = {{ prog }} {% endfor %} [gitlab-unicorn-startup] recipe = slapos.recipe.template:jinja2 mode = 0755 template= {{ gitlab_unicorn_startup_in }} rendered= ${directory:bin}/${:_buildout_section_name_} context = raw bash_bin {{ bash_bin }} raw gitlab_rake ${gitlab-rake:wrapper-path} raw gitlab_unicorn ${gitlab-unicorn:wrapper-path} raw psql_bin {{ postgresql_location }}/bin/psql section pgsql service-postgresql raw log_dir ${gitlab:log} raw var_dir ${directory:var} section unicorn_rb unicorn.rb section gitlab_work gitlab-work # 4. gitlab- & gitlab-shell- work directories # # Gitlab/Rails operation is tightened that config/ lives inside code, which goes # against having ability to create several instances configured differently # from 1 SR. # # One possibility to overcome this could be to make another Gitlab root # symbolically linked to original SR _and_ several configuration files # symbolically linked to instance place. Unfortunately this does not work - # Ruby determines realpath on module import and Gitlab and Rails lookup config # files relative to imported modules. # # we clone cloned gitlab and add proper links to vendor/bundle and instance # config files. # XXX there is no need for full clone - we only need worktree checkout (a-la `git # worktree add`, but without creating files in original clone) # # This way Gitlab/Rails still think they work in 1 code / 1 instance way, # and we can reuse SR. # XXX better do such tricks with bind mounting, but that requires user namespaces [work-base] recipe = plone.recipe.command stop-on-error = yes location = ${directory:home}/${:_buildout_section_name_} command = # make sure we start from well-defined empty state # (needed e.g. if previous install failed in the middle) rm -rf ${:location} && # init work repository and add `software` remote pointing to main repo in SR software/... {{ git }} init ${:location} && cd ${:location} && {{ git }} remote add software ${:software} && ${:update-command} update-command = cd ${:location} && {{ git }} fetch software && {{ git }} reset --hard `cd ${:software} && {{ git }} rev-parse HEAD` && ${:tune-command} # NOTE there is no need to link/create .gitlab_shell_secret - we set path to it # in gitlab & gitlab-shell configs, and gitlab creates it on its first start [gitlab-work] <= work-base software = {{ gitlab_repository_location }} tune-command = # Initialise secrets if [ ! -s "${secrets:secrets}/gitlab_secrets.yml" ]; then cp config/secrets.yml.example ${secrets:secrets}/gitlab_secrets.yml; fi # secret* tmp/ log/ shared/ builds/ node_modules/ rm -f .secret && rm -rf log tmp shared builds node_modules && # ln -sf ${secrets:secrets}/gitlab_rails_secret .secret && ln -sf ${gitlab:log} log && ln -sf ${gitlab:tmp} tmp && ln -sf ${gitlab:shared} shared && ln -sf ${gitlab:builds} builds && ln -sf {{ gitlab_repository_location }}/node_modules node_modules && ln -sf ${gitlab-workhorse:secret} .gitlab_workhorse_secret && # config/ cd config && ln -sf ${unicorn.rb:rendered} unicorn.rb && ln -sf ${gitlab.yml:rendered} gitlab.yml && ln -sf ${database.yml:rendered} database.yml && ln -sf ${resque.yml:rendered} resque.yml && ln -sf ${secrets:secrets}/gitlab_secrets.yml secrets.yml && # config/initializers/ cd initializers && # ln -sf ${rack_attack.rb:rendered} rack_attack.rb && ln -sf ${smtp_settings.rb:rendered} smtp_settings.rb && # public/ cd ../../public && rm -rf uploads assets && ln -sf ${gitlab:uploads} uploads && ln -sf ${gitlab:assets} assets && true # ----//---- for gitlab-shell [gitlab-shell-work] <= work-base software = {{ gitlab_shell_repository_location }} tune-command = cp ${:software}/bin/* bin && ln -sf ${gitlab-shell-config.yml:rendered} config.yml && true # 5. services # [promise-<something>] to check <something> by url [promise-byurl] <= monitor-promise-base module = check_command_execute name = ${:_buildout_section_name_}.py config-http_code = 200 ##################### # Postgresql db # ##################### # XXX gitlab-omnibus also tunes: # - shared_buffers # - work_mem # - checkpoint_* # - effective_check_size # - lc_* en_US.UTF-8 -> C (?) [service-postgresql] recipe = slapos.cookbook:postgres bin = {{ postgresql_location }}/bin services= ${directory:service} dbname = gitlabhq_production # NOTE db name must match to what was used in KVM on lab.nexedi.com (restore script grants access to this user) superuser = gitlab-psql # no password - pgsql will listen only on unix sockets (see below) thus access # is protected with filesystem-level permissions. # ( besides, if we use slapos.cookbook:generate.password and do `password = ...` # the password is stored in plain text in .installed and thus becomes insecure ) password= pgdata-directory = ${directory:srv}/postgresql # empty addresses - listen only on unix socket ipv4 = ipv6 = port = depend = ${promise-postgresql:recipe} [promise-postgresql] <= monitor-promise-base module = check_command_execute name = promise-postgresql.py config-command = {{ postgresql_location }}/bin/psql \ -h ${service-postgresql:pgdata-directory} \ -U ${service-postgresql:superuser} \ -d ${service-postgresql:dbname} \ -c '\q' # postgresql logs to stdout/stderr - logs are handled by slapos not us # [logrotate-entry-postgresql] ############# # Redis # ############# [redis] recipe = slapos.cookbook:mkdirectory srv = ${directory:srv}/redis log = ${directory:log}/redis [service-redis] recipe = slapos.cookbook:redis.server wrapper = ${directory:service}/redis promise_wrapper = ${directory:bin}/redis-promise server_dir = ${redis:srv} config_file = ${directory:etc}/redis.conf log_file = ${redis:log}/redis.log pid_file = ${directory:run}/redis.pid use_passwd = false unixsocket = ${:server_dir}/redis.socket # port = 0 means "don't listen on TCP at all" - listen only on unix socket ipv6 = ::1 port = 0 server_bin = {{ redis_binprefix }}/redis-server depend = ${logrotate-entry-redis:recipe} [promise-redis] <= monitor-promise-base module = check_command_execute name = promise-redis.py config-command = ${service-redis:promise_wrapper} # NOTE slapos.cookbook:redis.server setups promise automatically [logrotate-entry-redis] <= logrotate-entry-base log = ${redis:log}/*.log name = redis truncate = true ######################## # gitlab-workhorse # ######################## [gitlab-workhorse-dir] recipe = slapos.cookbook:mkdirectory srv = ${directory:srv}/gitlab-workhorse log = ${directory:log}/workhorse [gitlab-workhorse] srv = ${gitlab-workhorse-dir:srv} socket = ${gitlab-workhorse:srv}/gitlab-workhorse.socket log = ${gitlab-workhorse-dir:log}/gitlab-workhorse.log secret = ${secrets:secrets}/gitlab_workhorse_secret [service-gitlab-workhorse] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:service}/gitlab-workhorse command-line = {{ gitlab_workhorse }} -listenNetwork unix -listenAddr ${gitlab-workhorse:socket} -authSocket ${unicorn:socket} -documentRoot ${gitlab-work:location}/public -secretPath ${gitlab-workhorse:secret} -logFile ${gitlab-workhorse:log} # -repoPath ${gitlab-repo-dir:repositories} # NOTE for profiling # -pprofListenAddr ... # NOTE environment for: # - git to be available on path # - ruby to be available on path (gitlab-workhorse -> gitlab-shell -> hooks on push) # - gitconfig be found from ~/.gitconfig environment = PATH={{ git_location }}/bin:{{ ruby_location }}/bin:{{ gzip_location }}/bin:{{ bzip2_location}}/bin HOME=${directory:home} depend = ${promise-gitlab-workhorse:recipe} ${logrotate-entry-gitlab-workhorse:recipe} [promise-gitlab-workhorse] <= promise-byurl # http://localhost/users/statics.css will not redirect to /users/sign_in anymore because of this commit: # https://lab.nexedi.com/nexedi/gitlab-workhorse/commit/c81f109a62fecf2a847fb17ceed012b380dab49f#c1215002e6d745f05eaaf9ee1dad7752e85d866f_318_331 config-command = {{ curl_bin }} --unix-socket ${gitlab-workhorse:socket} http://localhost/users/sign_in # gitlab-workhorse logs to stdout/stderr - logs are handled by slapos not us # [logrotate-entry-gitlab-workhorse] ###################### # unicorn worker # ###################### [unicorn-dir] recipe = slapos.cookbook:mkdirectory srv = ${directory:srv}/unicorn log = ${directory:log}/unicorn [unicorn] srv = ${unicorn-dir:srv} log = ${unicorn-dir:log} socket = ${:srv}/unicorn.socket [service-unicorn] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:service}/unicorn # NOTE we perform db setup / migrations as part of unicorn startup. # Those operations require PG and Redis to be up and running already, that's # why we do it here. See gitlab-unicorn-startup for details. command-line = ${gitlab-unicorn-startup:rendered} depend = ${promise-unicorn:recipe} ${promise-gitlab-app:recipe} ${promise-gitlab-shell:recipe} ${logrotate-entry-unicorn:recipe} # gitlab is a service "run" under unicorn # gitlab-shell is called by gitlab # -> associate their logs rotation to here ${logrotate-entry-gitlab:recipe} [promise-unicorn] <= promise-byurl config-command = {{ curl_bin }} --unix-socket ${unicorn:socket} http://localhost/ [promise-rakebase] recipe = slapos.cookbook:wrapper # FIXME gitlab-rake is too slow to load and promise timeouts # that's why we instantiate to <promise>.slow/ (and this way promises are not run) wrapper-path = !py!'${directory:promise.slow}/' + '${:_buildout_section_name_}'[8:] rake = ${gitlab-rake:wrapper-path} [promise-gitlab-app] <= promise-rakebase command-line = ${:rake} gitlab:app:check [promise-gitlab-shell] <= promise-rakebase command-line = ${:rake} gitlab:gitlab_shell:check # very slow # rake gitlab:repo:check (fsck all repos) [logrotate-entry-unicorn] <= logrotate-entry-base log = ${unicorn:log}/*.log name = unicorn truncate = true [logrotate-entry-gitlab] <= logrotate-entry-base log = ${gitlab:log}/*.log name = gitlab truncate = true [logrotate-entry-gitlab-shell] <= logrotate-entry-base log = ${gitlab-shell:log}/*.log name = gitlab-shell truncate = true [logrotate-entry-gitlab-workhorse] <= logrotate-entry-base log = ${gitlab-workhorse-dir:log}//*.log name = gitlab-workhorse truncate = true ####################################### # sidekiq background jobs manager # ####################################### [sidekiq-dir] recipe = slapos.cookbook:mkdirectory log = ${directory:log}/sidekiq [sidekiq] log = ${sidekiq-dir:log} # NOTE see queue list here: # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/Procfile # https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-cookbooks/gitlab/templates/default/sv-sidekiq-run.erb # (last updated for omnibus-gitlab 8.8.9+ce.0-g25376053) [service-sidekiq] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:service}/sidekiq command-line = # NOTE Sidekiq memory killer makes sidekiq processes to exit, or if exit request # not handled in time, to be SIGKILL terminated, and relies on managing service # to restart it. In slapos we don't have mechanism to set autorestart=true, nor # bang/watchdog currently work with slapproxy, so we do the monitoring ourselves. {{ watcher }} 0,SIGKILL ${gitlab-sidekiq:wrapper-path} # XXX -q runner ? (present in gitlab-ce/Procfile but not in omnibus) # XXX -q pages -q elasticsearch ? (present in omnibus but not in gitlab-ce -- those features are gitlab-ee only) # XXX -P ? (pidfile) -e production -r ${gitlab-work:location} -t ${instance-parameter:configuration.sidekiq_shutdown_timeout} -c ${instance-parameter:configuration.sidekiq_concurrency} -L ${sidekiq:log}/sidekiq.log -C ${gitlab-work:location}/config/sidekiq_queues.yml depend = ${promise-sidekiq:recipe} ${logrotate-entry-sidekiq:recipe} wait-for-files = ${directory:var}/gitlab_db_ok [promise-sidekiq] <= promise-rakebase command-line = ${:rake} gitlab:sidekiq:check [logrotate-entry-sidekiq] <= logrotate-entry-base log = ${sidekiq:log}/*.log name = sidekiq truncate = true ###################### # Nginx frontend # ###################### # srv/nginx/ prefix + etc/ log/ ... [nginx-dir] recipe = slapos.cookbook:mkdirectory srv = ${directory:srv}/nginx etc = ${directory:etc}/nginx log = ${directory:log}/nginx [nginx-ssl-dir] recipe = slapos.cookbook:mkdirectory ssl = ${nginx-dir:etc}/ssl # contains https key mode = 0700 # self-signed certificate for https [nginx-generate-certificate] # NOTE there is slapos.cookbook:certificate_authority.request but it requires # to start whole service and has up to 60 seconds latency to generate # certificate. We only need to run 1 command to do it... recipe = plone.recipe.command stop-on-error = true cert_file = ${nginx-ssl-dir:ssl}/gitlab_backend.crt key_file = ${nginx-ssl-dir:ssl}/gitlab_backend.key command = test -e ${:key_file} || \ {{ openssl_bin }} req -newkey rsa -batch -new -x509 -days 3650 -nodes \ -keyout ${:key_file} -out ${:cert_file} update-command = ${:command} [nginx] srv = ${nginx-dir:srv} etc = ${nginx-dir:etc} log = ${nginx-dir:log} ssl = ${nginx-ssl-dir:ssl} cert_file = ${nginx-generate-certificate:cert_file} key_file = ${nginx-generate-certificate:key_file} [nginx-symlinks] # (nginx wants <prefix>/logs to be there from start - else it issues alarm to the log) recipe = cns.recipe.symlink symlink = ${nginx:log} = ${nginx:srv}/logs [service-nginx] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:service}/nginx command-line = {{ nginx_bin }} -p ${nginx:srv} -c ${nginx.conf:rendered} depend = ${nginx-symlinks:recipe} ${promise-nginx:recipe} ${logrotate-entry-nginx:recipe} [promise-nginx] <= promise-byurl # XXX this depends on gitlab-workhorse being up # (nginx is configured to proxy all requests to gitlab-workhorse) config-url = ${backend-info:url}/users/sign_in module = check_url_available [logrotate-entry-nginx] <= logrotate-entry-base log = ${nginx:log}/*.log name = nginx post = kill -USR1 $(cat ${directory:run}/nginx.pid) # base entry for clients who registers to cron [cron-entry] recipe = slapos.cookbook:cron.d # name = <section-name>.strip_prefix('cron-entry-') # XXX len() is not available in !py! - 11 hardcoded name = !py!'${:_buildout_section_name_}' [11:] # NOTE _not_ ${service-cron:cron-entries} - though the value is the same we do # not want service-cron to be instantiated just if a cron-entry is registered. cron-entries = ${cron:cron-entries} ###################### # gitaly worker # ###################### # https://docs.gitlab.com/ee/install/installation.html [service-gitaly] recipe = slapos.cookbook:wrapper wrapper-path = ${directory:service}/gitaly command-line = {{ gitaly_location }}/gitaly ${gitaly-config.toml:rendered} environment = PATH={{ bundler_1_17_3_dir }}:{{ ruby_location }}/bin:/bin:/usr/bin LD_LIBRARY_PATH={{ gcc_location }}/lib:{{ gcc_location }}/lib64 # 6. on-reinstantiate actions # NOTE here we only recompile assets. Other on-reinstantiate actions, which # require pg and redis running, are performed as part of unicorn service - # right before its startup (see gitlab-unicorn-startup). [on-reinstantiate] recipe = plone.recipe.command stop-on-error = true rake = ${gitlab-rake:wrapper-path} # run command on every reinstantiation update-command = ${:command} command = ${:rake} gitlab:assets:clean && ${:rake} gettext:compile RAILS_ENV=production && cd ${gitlab-work:location} && PATH={{ node_bin_location }}:$PATH {{ yarn_location }}/bin/yarn install --production --pure-lockfile && ${:rake} gitlab:assets:compile NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096" && true # Promise, gitlab can connect to gitaly: # sudo gitlab-rake gitlab:tcp_check[GITALY_SERVER_IP,GITALY_LISTEN_PORT]