Fix: packaging offline in new prepare

This new prepare script now support offline packaging

Signed-off-by: Qian Deng <dengq@vmware.com>
This commit is contained in:
Qian Deng 2019-03-18 15:07:19 +08:00
parent 0c84751a10
commit fcdab4d4af
14 changed files with 107 additions and 64 deletions

View File

@ -32,7 +32,7 @@ env:
- HARBOR_ADMIN: admin
- HARBOR_ADMIN_PASSWD: Harbor12345
- CORE_SECRET: tempString
- KEY_PATH: "/data/secretkey"
- KEY_PATH: "/data/secret/keys/secretkey"
- REDIS_HOST: localhost
- REG_VERSION: v2.7.1
- UI_BUILDER_VERSION: 1.6.0

View File

@ -65,6 +65,7 @@ SHELL := /bin/bash
BUILDPATH=$(CURDIR)
MAKEPATH=$(BUILDPATH)/make
MAKEDEVPATH=$(MAKEPATH)/dev
MAKE_PREPARE_PATH=$(MAKEPATH)/photon/prepare
SRCPATH=./src
TOOLSPATH=$(BUILDPATH)/tools
CORE_PATH=$(BUILDPATH)/src/core
@ -94,6 +95,8 @@ UIVERSIONTAG=dev
VERSIONFILEPATH=$(CURDIR)
VERSIONFILENAME=UIVERSION
PREPARE_VERSION_NAME=versions
#versions
REGISTRYVERSION=v2.7.1
NGINXVERSION=$(VERSIONTAG)
@ -107,6 +110,14 @@ NOTARYMIGRATEVERSION=v3.5.4
# version of chartmuseum
CHARTMUSEUMVERSION=v0.8.1
define VERSIONS_FOR_PREPARE
VERSION_TAG: $(VERSIONTAG)
REGISTRY_VERSION: $(REGISTRYVERSION)
NOTARY_VERSION: $(NOTARYVERSION)
CLAIR_VERSION: $(CLAIRVERSION)
CHARTMUSEUM_VERSION: $(CHARTMUSEUMVERSION)
endef
# docker parameters
DOCKERCMD=$(shell which docker)
DOCKERBUILD=$(DOCKERCMD) build
@ -175,6 +186,7 @@ MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
# docker image name
DOCKER_IMAGE_NAME_PREPARE=goharbor/prepare
DOCKERIMAGENAME_PORTAL=goharbor/harbor-portal
DOCKERIMAGENAME_CORE=goharbor/harbor-core
DOCKERIMAGENAME_JOBSERVICE=goharbor/harbor-jobservice
@ -209,7 +221,8 @@ REGISTRYUSER=user
REGISTRYPASSWORD=default
# cmds
DOCKERSAVE_PARA=$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
DOCKERSAVE_PARA=$(DOCKER_IMAGE_NAME_PREPARE):$(VERSIONTAG) \
$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
$(DOCKERIMAGENAME_CORE):$(VERSIONTAG) \
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
@ -246,9 +259,13 @@ ifeq ($(CHARTFLAG), true)
DOCKERSAVE_PARA+= $(DOCKERIMAGENAME_CHART_SERVER):$(CHARTMUSEUMVERSION)-$(VERSIONTAG)
endif
export VERSIONS_FOR_PREPARE
ui_version:
@printf $(UIVERSIONTAG) > $(VERSIONFILEPATH)/$(VERSIONFILENAME);
versions_prepare:
@echo "$$VERSIONS_FOR_PREPARE" > $(MAKE_PREPARE_PATH)/$(PREPARE_VERSION_NAME)
check_environment:
@$(MAKEPATH)/$(CHECKENVCMD)
@ -274,9 +291,13 @@ compile_notary_migrate_patch:
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_MIGRATEPATCH) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -o $(GOBUILDMAKEPATH_NOTARY)/$(MIGRATEPATCHBINARYNAME)
@echo "Done."
compile:check_environment compile_core compile_jobservice compile_registryctl compile_notary_migrate_patch
prepare:
compile: check_environment versions_prepare compile_core compile_jobservice compile_registryctl compile_notary_migrate_patch
update_prepare_version:
@echo "substitude the prepare version tag in prepare file..."
$(SEDCMD) -i -e 's/goharbor\/prepare:.*[[:space:]]\+/goharbor\/prepare:$(VERSIONTAG) /' $(MAKEPATH)/prepare ;
prepare: update_prepare_version
@echo "preparing..."
@$(MAKEPATH)/$(PREPARECMD) $(PREPARECMD_PARA)
@ -297,12 +318,13 @@ package_online: prepare
$(HARBORPKG)/docker-compose.yml ; \
fi
@cp LICENSE $(HARBORPKG)/LICENSE
@$(TARCMD) $(PACKAGE_ONLINE_PARA)
@rm -rf $(HARBORPKG)
@echo "Done."
package_offline: compile ui_version build
package_offline: update_prepare_version compile ui_version build
@echo "packing offline package ..."
@cp -r make $(HARBORPKG)
@cp LICENSE $(HARBORPKG)/LICENSE
@ -360,6 +382,11 @@ govet:
pushimage:
@echo "pushing harbor images ..."
@$(DOCKERTAG) $(DOCKER_IMAGE_NAME_PREPARE):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKER_IMAGE_NAME_PREPARE):$(VERSIONTAG)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKER_IMAGE_NAME_PREPARE):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKER_IMAGE_NAME_PREPARE):$(VERSIONTAG)
@$(DOCKERTAG) $(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)

View File

@ -49,8 +49,8 @@ note() { printf "\n${underline}${bold}${blue}Note:${reset} ${blue}%s${reset}\n"
set -e
set +o noglob
usage=$'Please set hostname and other necessary attributes in harbor.cfg first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.
Please set --with-notary if needs enable Notary in Harbor, and set ui_url_protocol/ssl_cert/ssl_cert_key in harbor.cfg bacause notary must run under https.
usage=$'Please set hostname and other necessary attributes in harbor.yml first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.
Please set --with-notary if needs enable Notary in Harbor, and set ui_url_protocol/ssl_cert/ssl_cert_key in harbor.yml bacause notary must run under https.
Please set --with-clair if needs enable Clair in Harbor
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor'
item=0
@ -83,8 +83,8 @@ done
workdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $workdir
# The hostname in harbor.cfg has not been modified
if grep '^[[:blank:]]*hostname = reg.mydomain.com' &> /dev/null harbor.cfg
# The hostname in harbor.yml has not been modified
if grep '^[[:blank:]]*hostname: reg.mydomain.com' &> /dev/null harbor.yml
then
warn "$usage"
exit 1
@ -160,7 +160,7 @@ echo ""
h2 "[Step $item]: preparing environment ..."; let item+=1
if [ -n "$host" ]
then
sed "s/^hostname = .*/hostname = $host/g" -i ./harbor.cfg
sed "s/^hostname: .*/hostname = $host/g" -i ./harbor.yml
fi
prepare_para=
if [ $with_notary ]
@ -192,12 +192,12 @@ docker-compose up -d
protocol=http
hostname=reg.mydomain.com
if [[ $(cat ./harbor.cfg) =~ ui_url_protocol[[:blank:]]*=[[:blank:]]*(https?) ]]
if [[ $(cat ./harbor.yml) =~ ui_url_protocol:[[:blank:]]*(https?) ]]
then
protocol=${BASH_REMATCH[1]}
fi
if [[ $(grep '^[[:blank:]]*hostname[[:blank:]]*=' ./harbor.cfg) =~ hostname[[:blank:]]*=[[:blank:]]*(.*) ]]
if [[ $(grep '^[[:blank:]]*hostname:' ./harbor.yml) =~ hostname:[[:blank:]]*(.*) ]]
then
hostname=${BASH_REMATCH[1]}
fi

View File

@ -32,6 +32,10 @@ JOBSERVICEBINARYNAME=harbor_jobservice
# photon dockerfile
DOCKERFILEPATH=$(MAKEPATH)/photon
DOCKERFILEPATH_PREPARE=$(DOCKERFILEPATH)/prepare
DOCKERFILENAME_PREPARE=Dockerfile
DOCKERIMAGENAME_PREPARE=goharbor/prepare
DOCKERFILEPATH_PORTAL=$(DOCKERFILEPATH)/portal
DOCKERFILENAME_PORTAL=Dockerfile
DOCKERIMAGENAME_PORTAL=goharbor/harbor-portal
@ -93,6 +97,11 @@ CHART_SERVER_CODE_BASE=github.com/helm/chartmuseum
CHART_SERVER_MAIN_PATH=cmd/chartmuseum
CHART_SERVER_BIN_NAME=chartm
_build_prepare:
@echo "building prepare container for photon..."
@$(DOCKERBUILD) -f $(DOCKERFILEPATH_PREPARE)/$(DOCKERFILENAME_PREPARE) -t $(DOCKERIMAGENAME_PREPARE):$(VERSIONTAG) .
@echo "Done."
_build_db:
@echo "building db container for photon..."
@$(DOCKERBUILD) -f $(DOCKERFILEPATH_DB)/$(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) .
@ -200,7 +209,7 @@ define _get_binary
$(WGET) --timeout 30 --no-check-certificate $1 -O $2
endef
build: _build_db _build_portal _build_core _build_jobservice _build_log _build_nginx _build_registry _build_registryctl _build_notary _build_clair _build_redis _build_migrator _build_chart_server
build: _build_prepare _build_db _build_portal _build_core _build_jobservice _build_log _build_nginx _build_registry _build_registryctl _build_notary _build_clair _build_redis _build_migrator _build_chart_server
cleanimage:
@echo "cleaning image for photon..."

View File

@ -8,9 +8,9 @@ RUN mkdir -p /harbor_make
RUN tdnf install -y python3 \
&& tdnf install -y python3-pip
RUN pip3 install pipenv
RUN pip3 install pipenv==2018.11.26
COPY . /usr/src/app
COPY make/photon/prepare /usr/src/app
RUN set -ex && pipenv install --deploy --system
ENTRYPOINT [ "python3", "main.py" ]

View File

@ -20,6 +20,7 @@ private_key_pem_path = Path('/secret/core/private_key.pem')
root_crt_path = Path('/secret/registry/root.crt')
config_file_path = '/compose_location/harbor.yml'
versions_file_path = Path('/usr/src/app/versions')
cert_dir = os.path.join(config_dir, "nginx", "cert")
core_cert_dir = os.path.join(config_dir, "core", "certificates")

View File

@ -1,3 +1,5 @@
# pylint: disable=no-value-for-parameter
import click
from utils.misc import delfile
@ -8,14 +10,13 @@ from utils.jobservice import prepare_job_service
from utils.registry import prepare_registry
from utils.registry_ctl import prepare_registry_ctl
from utils.core import prepare_core
from utils.uaa import prepare_uaa_cert_file
from utils.notary import prepare_notary
from utils.log import prepare_log_configs
from utils.clair import prepare_clair
from utils.chart import prepare_chartmuseum
from utils.docker_compose import prepare_docker_compose
from utils.nginx import prepare_nginx, nginx_confd_dir
from g import (config_dir, config_file_path, core_cert_dir, private_key_pem_path, root_crt_path,
from g import (config_dir, config_file_path, private_key_pem_path, root_crt_path,
registry_custom_ca_bundle_storage_path, registry_custom_ca_bundle_storage_input_path, secret_key_dir,
old_private_key_pem_path, old_crt_path)

View File

@ -51,7 +51,10 @@ def get_alias(path):
return alias
def copy_secret_keys():
if os.path.isdir(secret_cert) and os.path.isdir(input_secret_keys_dir):
"""
Copy the secret keys, which used for encrypt user password, from input keys dir to secret keys dir
"""
if os.path.isdir(input_secret_keys_dir) and os.path.isdir(secret_keys_dir):
input_files = os.listdir(input_secret_keys_dir)
secret_files = os.listdir(secret_keys_dir)
files_need_copy = [x for x in input_files if (x in allowed_secret_key_names) and (x not in secret_files) ]
@ -59,6 +62,9 @@ def copy_secret_keys():
shutil.copy(f, secret_keys_dir)
def copy_ssl_cert():
"""
Copy the ssl certs key paris, which used in nginx ssl certificate, from input dir to secret cert dir
"""
if os.path.isfile(input_cert_key) and os.path.isfile(input_cert):
os.makedirs(secret_cert_dir, exist_ok=True)
shutil.copy(input_cert, secret_cert)
@ -79,26 +85,26 @@ def stat_decorator(func):
@stat_decorator
def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"):
rc = subprocess.call(["openssl", "genrsa", "-out", key_path, "4096"], stdout=DEVNULL, stderr=subprocess.STDOUT)
rc = subprocess.call(["/usr/bin/openssl", "genrsa", "-out", key_path, "4096"], stdout=DEVNULL, stderr=subprocess.STDOUT)
if rc != 0:
return rc
return subprocess.call(["openssl", "req", "-new", "-x509", "-key", key_path,\
return subprocess.call(["/usr/bin/openssl", "req", "-new", "-x509", "-key", key_path,\
"-out", cert_path, "-days", "3650", "-subj", subj], stdout=DEVNULL, stderr=subprocess.STDOUT)
@stat_decorator
def create_cert(subj, ca_key, ca_cert, key_path="./k.key", cert_path="./cert.crt"):
cert_dir = os.path.dirname(cert_path)
csr_path = os.path.join(cert_dir, "tmp.csr")
rc = subprocess.call(["openssl", "req", "-newkey", "rsa:4096", "-nodes","-sha256","-keyout", key_path,\
rc = subprocess.call(["/usr/bin/openssl", "req", "-newkey", "rsa:4096", "-nodes","-sha256","-keyout", key_path,\
"-out", csr_path, "-subj", subj], stdout=DEVNULL, stderr=subprocess.STDOUT)
if rc != 0:
return rc
return subprocess.call(["openssl", "x509", "-req", "-days", "3650", "-in", csr_path, "-CA", \
return subprocess.call(["/usr/bin/openssl", "x509", "-req", "-days", "3650", "-in", csr_path, "-CA", \
ca_cert, "-CAkey", ca_key, "-CAcreateserial", "-out", cert_path], stdout=DEVNULL, stderr=subprocess.STDOUT)
def openssl_installed():
shell_stat = subprocess.check_call(["which", "openssl"], stdout=DEVNULL, stderr=subprocess.STDOUT)
shell_stat = subprocess.check_call(["/usr/bin/which", "openssl"], stdout=DEVNULL, stderr=subprocess.STDOUT)
if shell_stat != 0:
print("Cannot find openssl installed in this computer\nUse default SSL certificate file")
return False
@ -124,8 +130,9 @@ def prepare_ca(
create_root_cert(empty_subj, key_path=private_key_pem_path, cert_path=root_crt_path)
mark_file(private_key_pem_path)
mark_file(root_crt_path)
shutil.move(old_crt_path, root_crt_path)
shutil.move(old_private_key_pem_path, private_key_pem_path)
else:
shutil.move(old_crt_path, root_crt_path)
shutil.move(old_private_key_pem_path, private_key_pem_path)
if not registry_custom_ca_bundle_storage_path.exists() and registry_custom_ca_bundle_config.exists():

View File

@ -1,4 +1,5 @@
import yaml, configparser
import yaml
from g import versions_file_path
from .misc import generate_random_string
def validate(conf, **kwargs):
@ -41,6 +42,12 @@ def validate(conf, **kwargs):
raise Exception(
"Error invalid value for redis_db_index: %s. please set it as 1,2,3" % redis_db_index)
def parse_versions():
if not versions_file_path.is_file():
return {}
with open('versions') as f:
versions = yaml.load(f)
return versions
def parse_yaml_config(config_file_path):
'''

View File

@ -1,37 +1,28 @@
import os
from g import templates_dir
from .configs import parse_versions
from .jinja import render_jinja
# render docker-compose
VERSION_TAG = 'dev'
REGISTRY_VERSION = 'v2.7.1'
NOTARY_VERSION = 'v0.6.1-v1.7.1'
CLAIR_VERSION = 'v2.0.7-dev'
CHARTMUSEUM_VERSION = 'v0.8.1-dev'
CLAIR_DB_VERSION = VERSION_TAG
MIGRATOR_VERSION = VERSION_TAG
REDIS_VERSION = VERSION_TAG
NGINX_VERSION = VERSION_TAG
# version of chartmuseum
docker_compose_template_path = os.path.join(templates_dir, 'docker_compose', 'docker-compose.yml.jinja')
docker_compose_yml_path = '/compose_location/docker-compose.yml'
def check_configs(configs):
pass
# render docker-compose
def prepare_docker_compose(configs, with_clair, with_notary, with_chartmuseum):
check_configs(configs)
versions = parse_versions()
VERSION_TAG = versions.get('VERSION_TAG') or 'dev'
REGISTRY_VERSION = versions.get('REGISTRY_VERSION') or 'v2.7.1'
NOTARY_VERSION = versions.get('NOTARY_VERSION') or 'v0.6.1'
CLAIR_VERSION = versions.get('CLAIR_VERSION') or 'v2.0.7'
CHARTMUSEUM_VERSION = versions.get('CHARTMUSEUM_VERSION') or 'v0.8.1'
rendering_variables = {
'version': VERSION_TAG,
'reg_version': "{}-{}".format(REGISTRY_VERSION, VERSION_TAG),
'redis_version': REDIS_VERSION,
'notary_version': NOTARY_VERSION,
'clair_version': CLAIR_VERSION,
'chartmuseum_version': CHARTMUSEUM_VERSION,
'redis_version': VERSION_TAG,
'notary_version': '{}-{}'.format(NOTARY_VERSION, VERSION_TAG),
'clair_version': '{}-{}'.format(CLAIR_VERSION, VERSION_TAG),
'chartmuseum_version': '{}-{}'.format(CHARTMUSEUM_VERSION, VERSION_TAG),
'data_volume': configs['data_volume'],
'log_location': configs['log_location'],
'cert_key_path': configs['cert_key_path'],

View File

@ -12,7 +12,6 @@ def mark_file(path, mode=0o600, uid=DEFAULT_UID, gid=DEFAULT_GID):
os.chmod(path, mode)
if uid > 0 and gid > 0:
os.chown(path, uid, gid)
pass
def validate(conf, **kwargs):
@ -98,8 +97,8 @@ def delfile(src):
try:
os.remove(src)
print("Clearing the configuration file: %s" % src)
except:
pass
except Exception as e:
print(e)
elif os.path.isdir(src):
for item in os.listdir(src):
itemsrc = os.path.join(src, item)

View File

@ -1,5 +1,5 @@
import os, shutil, pathlib
from g import base_dir, templates_dir, config_dir, root_crt_path, secret_key_dir,DEFAULT_UID, DEFAULT_GID
from g import templates_dir, config_dir, root_crt_path, secret_key_dir,DEFAULT_UID, DEFAULT_GID
from .cert import openssl_installed, create_cert, create_root_cert, get_alias
from .jinja import render_jinja
from .misc import mark_file, prepare_config_dir
@ -29,8 +29,6 @@ def prepare_env_notary(customize_crt, nginx_config_dir):
signer_cert_secret_path = pathlib.Path(os.path.join(notary_secret_dir, 'notary-signer.crt'))
signer_key_secret_path = pathlib.Path(os.path.join(notary_secret_dir, 'notary-signer.key'))
signer_ca_cert_secret_path = pathlib.Path(os.path.join(notary_secret_dir, 'notary-signer-ca.crt'))
notary_root_cert_secret_path = pathlib.Path(os.path.join(notary_secret_dir, 'root.crt'))
# In version 1.8 the secret path changed
# If cert, key , ca all are exist in new place don't do anything
@ -46,7 +44,7 @@ def prepare_env_notary(customize_crt, nginx_config_dir):
shutil.copy2(old_signer_key_secret_path, signer_key_secret_path)
shutil.copy2(old_signer_cert_secret_path, signer_cert_secret_path)
# If certs neither exist in new place nor in the old place, create it and move it to new place
else:
elif openssl_installed():
try:
temp_cert_dir = os.path.join('/tmp', "cert_tmp")
if not os.path.exists(temp_cert_dir):
@ -69,6 +67,8 @@ def prepare_env_notary(customize_crt, nginx_config_dir):
os.remove(srl_tmp)
if os.path.isdir(temp_cert_dir):
shutil.rmtree(temp_cert_dir, True)
else:
raise(Exception("No certs for notary"))
# copy server_env to notary config
shutil.copy2(
@ -83,7 +83,6 @@ def prepare_env_notary(customize_crt, nginx_config_dir):
mark_file(os.path.join(notary_secret_dir, "notary-signer.crt"))
mark_file(os.path.join(notary_secret_dir, "notary-signer.key"))
mark_file(os.path.join(notary_secret_dir, "notary-signer-ca.crt"))
mark_file(os.path.join(notary_secret_dir, "root.crt"))
# print("Copying sql file for notary DB")
# if os.path.exists(os.path.join(notary_config_dir, "postgresql-initdb.d")):

View File

@ -11,6 +11,7 @@ secretkey_path=$(grep '^[^#]*secretkey_path:' ${harbor_prepare_path}/harbor.yml
ssl_cert_path=$(grep '^[^#]*ssl_cert:' ${harbor_prepare_path}/harbor.yml | awk '{print $NF}')
ssl_cert_key_path=$(grep '^[^#]*ssl_cert_key:' ${harbor_prepare_path}/harbor.yml | awk '{print $NF}')
registry_custom_ca_bundle=$(grep '^[^#]*registry_custom_ca_bundle:' ${harbor_prepare_path}/harbor.yml | awk '{print $NF}')
# Create a input dirs
mkdir -p ${harbor_prepare_path}/input
input_dir=${harbor_prepare_path}/input
@ -18,10 +19,6 @@ mkdir -p $input_dir/nginx
mkdir -p $input_dir/keys
mkdir -p $input_dir/common
# Create secret dir
secret_dir=${data_path}/secret
config_dir=$harbor_prepare_path/common/config
# Copy nginx config file to input dir
cp $ssl_cert_path $input_dir/nginx/server.crt
cp $ssl_cert_key_path $input_dir/nginx/server.key
@ -38,12 +35,17 @@ fi
# Copy harbor.yml to input dir
cp ${harbor_prepare_path}/harbor.yml $input_dir/harbor.yml
# Create secret dir
secret_dir=${data_path}/secret
config_dir=$harbor_prepare_path/common/config
# Run prepare script
docker run -it --rm -v $input_dir:/input \
-v $harbor_prepare_path:/compose_location \
-v $config_dir:/config \
-v $secret_dir:/secret \
-v $log_path:/var/log/harbor \
goharbor/prepare:1.7.1 $@
goharbor/prepare:dev $@
# Clean up input dir
rm -rf ${harbor_prepare_path}/input

View File

@ -3,7 +3,7 @@ set -e
cp tests/docker-compose.test.yml make/.
mkdir -p core
cp make/common/config/core/private_key.pem /etc/core/
cp /data/secret/core/private_key.pem /etc/core/
mkdir src/core/conf
cp make/common/config/core/app.conf src/core/conf/