Ejemplo n.º 1
0
    def __init__(self, file, data):
        super(DeepoMakeFile, self).__init__()

        self.__path__ = os.path.join(os.path.dirname(file), '')

        try:
            path = os.path.join(os.path.dirname(file), '')
            self._validate_(path, data)
        except ValidationError as e:
            raise DMakeException(("Error in %s:\n" % file) + str(e))

        if self.env.__has_value__:
            env = copy.deepcopy(self.env.default)
            if common.branch in self.env.branches:
                for var, value in self.env.branches[common.branch].items():
                    env[var] = value

            env_field = FieldSerializer("dict", child="string")
            env_field._validate_(self.__path__, env)
            self.__fields__['env'] = env_field
        else:
            self.__fields__['env'] = {}

        self.env_file = None
        self.docker_cmd = None
        self.docker_services_image = None
Ejemplo n.º 2
0
class EnvSerializer(YAML2PipelineSerializer):
    default = FieldSerializer(
        [
            FieldSerializer(
                "path",
                help_text=
                "to another deepomake file that declares a default environment."
            ), "dict"
        ],
        child="string",
        default={},
        post_validation=load_env,
        help_text="List of environment variables that will be set by default.",
        example={
            'MY_ENV_VARIABLE': '1',
            'ENV_TYPE': 'dev'
        })
    branches = FieldSerializer(
        "dict",
        child=FieldSerializer("dict", child="string"),
        default={},
        help_text=
        "If the branch matches one of the following fields, those variables will be defined as well, eventually replacing the default.",
        example={'master': {
            'ENV_TYPE': 'prod'
        }})
Ejemplo n.º 3
0
class DeployConfigVolumesSerializer(YAML2PipelineSerializer):
    container_volume = FieldSerializer("string",
                                       example="/mnt",
                                       help_text="Volume on the container")
    host_volume = FieldSerializer("string",
                                  example="/mnt",
                                  help_text="Volume on the host")
Ejemplo n.º 4
0
class SSHDeploySerializer(YAML2PipelineSerializer):
    user = FieldSerializer("string", example="ubuntu", help_text="User name")
    host = FieldSerializer("string",
                           example="192.168.0.1",
                           help_text="Host address")
    port = FieldSerializer("int", default="22", help_text="SSH port")

    def _serialize_(self, commands, tmp_dir, app_name, docker_links, config):
        if not self.has_value():
            return

        opts = config.full_docker_opts(False)

        launch_links = ""
        for link in docker_links:
            launch_links += 'if [ \\`docker ps -f name=%s | wc -l\\` = "1" ]; then set +e; docker rm -f %s 2> /dev/null ; set -e; docker run -d --name %s %s -i %s; fi\n' % (
                link.link_name, link.link_name, link.link_name,
                link.deployed_options, link.image_name)
            opts += " --link %s" % link.link_name

        common.run_shell_command(
            'export APP_NAME="%s" && export DOCKER_OPTS="%s" && export LAUNCH_LINK="%s" && export PRE_DEPLOY_HOOKS="%s" && export MID_DEPLOY_HOOKS="%s" && export POST_DEPLOY_HOOKS="%s" && deepomake_copy_template deploy/deploy_ssh/start_app.sh %s && deepomake_copy_template deploy/deploy_ssh/start_cmd.sh %s'
            %
            (app_name + "-%s" % common.branch.lower(), opts, launch_links,
             config.pre_deploy_script, config.mid_deploy_script,
             config.post_deploy_script, os.path.join(tmp_dir, "start_app.sh"),
             os.path.join(tmp_dir, "start_cmd.sh")))

        cmd = 'deepomake_deploy_ssh "%s" "%s" "%s" "%s"' % (
            tmp_dir, self.user, self.host, self.port)
        append_command(commands, 'sh', shell=cmd)
Ejemplo n.º 5
0
class DeployConfigPortsSerializer(YAML2PipelineSerializer):
    container_port = FieldSerializer("int",
                                     example=8000,
                                     help_text="Port on the container")
    host_port = FieldSerializer("int",
                                example=80,
                                help_text="Port on the host")
Ejemplo n.º 6
0
class ServicesSerializer(YAML2PipelineSerializer):
    service_name = FieldSerializer(
        "string",
        default="",
        help_text="The name of the application part.",
        example="api",
        no_slash_no_space=True)
    needed_services = FieldSerializer(
        "array",
        child=FieldSerializer("string", blank=False),
        default=[],
        help_text=
        "List here the sub apps (as defined by service_name) of our application that are needed for this sub app to run.",
        example=["worker"])
    sources = FieldSerializer(
        "array",
        child=FieldSerializer(["path", "dir"]),
        optional=True,
        help_text=
        "If specified, this service will be considered as updated only when the content of those directories or files have changed.",
        example='path/to/app')
    config = DeployConfigSerializer(optional=True,
                                    help_text="Deployment configuration.")
    tests = TestsSerializer(optional=True, help_text="Unit tests list.")
    deploy = DeploySerializer(optional=True, help_text="Deploy stage")
Ejemplo n.º 7
0
class DeploySerializer(YAML2PipelineSerializer):
    deploy_name = FieldSerializer(
        "string",
        optional=True,
        example="",
        help_text=
        "The name used for deployment. Will default to \"db-app_name-service_name\" if not specified"
    )
    stages = FieldSerializer("array",
                             child=DeployStageSerializer(),
                             help_text="Deployment possibilities")

    _tmp_dir_ = None

    def generate_build(self, commands, path_dir, app_name, service_name,
                       docker_base, env, config):
        if self._tmp_dir_ is not None:
            raise DMakeException('Build already generated')

        if config.docker_image.has_value():
            self._tmp_dir_ = config.docker_image.generate_build(
                commands, path_dir, app_name, service_name, docker_base, env,
                config)

    def generate_deploy(self, commands, app_name, service_name, docker_links,
                        env, config):
        if self._tmp_dir_ is None:
            raise DMakeException(
                'Sanity check failed: it seems the build step has been skipped: _tmp_dir_ is null.'
            )

        if self.deploy_name is not None:
            app_name = self.deploy_name
        else:
            app_name = "dp-%s-%s" % (app_name, service_name)

        links = []
        for link_name in config.docker_links_names:
            if link_name not in docker_links:
                raise DMakeException("Unknown link name: '%s'" % link_name)
            links.append(docker_links[link_name])

        for stage in self.stages:
            branches = stage.branches
            if common.branch not in branches and '*' not in branches:
                continue

            env = copy.deepcopy(env)
            for var, value in stage.env.items():
                env[var] = value
                os.environ[var] = value

            generate_dockerfile(commands, self._tmp_dir_, env)

            stage.aws_beanstalk._serialize_(commands, self._tmp_dir_, app_name,
                                            links, config)
            stage.ssh._serialize_(commands, self._tmp_dir_, app_name, links,
                                  config)
Ejemplo n.º 8
0
class HTMLReportSerializer(YAML2PipelineSerializer):
    directory = FieldSerializer("string",
                                example="reports",
                                help_text="Directory of the html pages.")
    index = FieldSerializer("string",
                            default="index.html",
                            help_text="Main page.")
    title = FieldSerializer("string",
                            default="HTML Report",
                            help_text="Main page title.")
Ejemplo n.º 9
0
class DockerRootImageSerializer(YAML2PipelineSerializer):
    name = FieldSerializer("string",
                           help_text="Root image name.",
                           example="library/ubuntu")
    tag = FieldSerializer(
        "string",
        help_text="Root image tag (you can use environment variables).")

    def full_name(self):
        full = self.name + ":" + self.tag
        return common.eval_str_in_env(full)
Ejemplo n.º 10
0
class TestsSerializer(YAML2PipelineSerializer):
    docker_links_names = FieldSerializer(
        "array",
        child="string",
        default=[],
        example=['mongo'],
        help_text=
        "The docker links names to bind to for this test. Must be declared at the root level of some deepomake file of the app."
    )
    docker_opts = FieldSerializer(
        "string",
        default="",
        example="--privileged",
        help_text="Docker options to add when testing or launching.")
    commands = FieldSerializer(
        "array",
        child="string",
        example=["python manage.py test"],
        help_text="The commands to run for integration tests.")
    junit_report = FieldSerializer(
        "string",
        optional=True,
        example="test-reports/*.xml",
        help_text="Uses JUnit plugin to generate unit test report.")
    cobertura_report = FieldSerializer(
        "string",
        optional=True,
        example="",
        help_text="Publish a Cobertura report (not working for now).")
    html_report = HTMLReportSerializer(optional=True,
                                       help_text="Publish an HTML report.")

    def generate_test(self, commands, app_name, docker_cmd, docker_links):
        for cmd in self.commands:
            d_cmd = "${DOCKER_LINK_OPTS} -e BUILD=%s -e DMAKE_TESTING=1 " % (
                common.build_id) + self.docker_opts + docker_cmd
            append_command(commands,
                           'sh',
                           shell="deepomake_run_docker_command " + d_cmd + cmd)

        if self.junit_report is not None:
            append_command(commands, 'junit', report=self.junit_report)

        if self.cobertura_report is not None:
            append_command(commands, 'cobertura', report=self.cobertura_report)

        html = self.html_report._value_()
        if html is not None:
            append_command(commands,
                           'publishHTML',
                           directory=html['directory'],
                           index=html['index'],
                           title=html['title'])
Ejemplo n.º 11
0
class DockerLinkSerializer(YAML2PipelineSerializer):
    image_name = FieldSerializer(
        "string",
        example="mongo:3.2",
        help_text="Name and tag of the image to launch.")
    link_name = FieldSerializer("string",
                                example="mongo",
                                help_text="Link name.")
    deployed_options = FieldSerializer(
        "string",
        default="",
        example="-v /mnt:/data",
        help_text="Additional Docker options when deployed.")
    testing_options = FieldSerializer(
        "string",
        default="",
        example="-v /mnt:/data",
        help_text="Additional Docker options when testing on Jenkins.")
Ejemplo n.º 12
0
class InstallDirSerializer(YAML2PipelineSerializer):
    dir_src = FieldSerializer(
        "dir",
        child_path_only=True,
        check_path=False,
        example="some/relative/directory/",
        help_text=
        "Path to the source directory (relative to this deepomake file) to copy."
    )
    dir_dst = FieldSerializer(
        "string",
        check_path=False,
        help_text="Path to the install directory (in the docker).")

    def docker_cmd(self, commands, path_dir, tmp_dir):
        generate_copy_command(commands,
                              path_dir,
                              tmp_dir,
                              self.dir_src,
                              recursive=True)
        return "ADD %s %s" % (self.dir_src, self.dir_dst)
Ejemplo n.º 13
0
class InstallLibSerializer(YAML2PipelineSerializer):
    lib = FieldSerializer(
        "path",
        child_path_only=True,
        check_path=False,
        example="some/relative/libexample.so",
        help_text=
        "Path to the executable to copy (will be copied in /usr/local/lib).")

    def docker_cmd(self, commands, path_dir, tmp_dir):
        generate_copy_command(commands, path_dir, tmp_dir, self.lib)
        return "COPY %s /usr/local/lib/" % self.lib
Ejemplo n.º 14
0
class DeployStageSerializer(YAML2PipelineSerializer):
    description = FieldSerializer("string",
                                  example="Deployment on AWS and via SSH",
                                  help_text="Deploy stage description.")
    branches = FieldSerializer(
        ["string", "array"],
        child="string",
        default=['stag'],
        post_validation=lambda x: [x] if common.is_string(x) else x,
        help_text=
        "Branch list for which this stag is active, '*' can be used to match any branch. Can also be a simple string."
    )
    env = FieldSerializer(
        "dict",
        child="string",
        default={},
        example={
            'AWS_ACCESS_KEY_ID': '1234',
            'AWS_SECRET_ACCESS_KEY': 'abcd'
        },
        help_text="Additionnal environment variables for deployment.")
    aws_beanstalk = AWSBeanStalkDeploySerializer(
        optional=True, help_text="Deploy via Elastic Beanstalk")
    ssh = SSHDeploySerializer(optional=True, help_text="Deploy via SSH")
Ejemplo n.º 15
0
class DockerBaseSerializer(YAML2PipelineSerializer):
    name = FieldSerializer(
        "string",
        help_text=
        "Base image name. If no docker user is indicated, the image will be kept locally"
    )
    version = FieldSerializer(
        "string",
        help_text=
        "Base image version. The branch name will be prefixed to form the docker image tag.",
        example="v2",
        default='latest')
    install_scripts = FieldSerializer("array",
                                      default=[],
                                      child=FieldSerializer(
                                          "path",
                                          executable=True,
                                          child_path_only=True),
                                      example=["some/relative/script/to/run"])
    python_requirements = FieldSerializer(
        "path",
        default="",
        child_path_only=True,
        help_text="Path to python requirements.txt.",
        example="")
    python3_requirements = FieldSerializer(
        "path",
        default="",
        child_path_only=True,
        help_text="Path to python requirements.txt.",
        example="requirements.txt")
    copy_files = FieldSerializer(
        "array",
        child=FieldSerializer("path", child_path_only=True),
        default=[],
        help_text=
        "Files to copy. Will be copied before scripts are ran. Paths need to be sub-paths to the build file to preserve MD5 sum-checking (which is used to decide if we need to re-build docker base image). A file 'foo/bar' will be copied in '/base/user/foo/bar'.",
        example=["some/relative/file/to/copy"])
Ejemplo n.º 16
0
class DeepoMakeFileSerializer(YAML2PipelineSerializer):
    dmake_version = FieldSerializer("string",
                                    help_text="The deepomake version.",
                                    example="0.1")
    app_name = FieldSerializer("string",
                               help_text="The application name.",
                               example="my_app",
                               no_slash_no_space=True)
    blacklist = FieldSerializer(
        "array",
        child="path",
        default=[],
        help_text="List of deepomake files to blacklist.",
        child_path_only=True,
        example=['some/sub/deepomake.yml'])
    env = EnvSerializer(
        help_text="Environment variables to embed in built docker images.")
    docker = FieldSerializer([
        FieldSerializer(
            "path",
            help_text=
            "to another deepomake file (which will be added to dependencies) that declares a docker field, in which case it replaces this file's docker field."
        ),
        DockerSerializer()
    ],
                             help_text=
                             "The environment in which to build and deploy.")
    docker_links = FieldSerializer(
        "array",
        child=DockerLinkSerializer(),
        default=[],
        help_text=
        "List of link to create, they are shared across the whole application, so potentially across multiple deepomake files."
    )
    build_tests_commands = FieldSerializer(
        "array",
        default=[],
        child=FieldSerializer(["string", "array"],
                              child="string",
                              post_validation=lambda x: [x]
                              if common.is_string(x) else x),
        help_text=
        "Command list (or list of lists, in which case each list of commands will be executed in paralell) to build.",
        example=["cmake .", "make"])
    build_services_commands = FieldSerializer(
        "array",
        default=[],
        child=FieldSerializer(["string", "array"],
                              child="string",
                              post_validation=lambda x: [x]
                              if common.is_string(x) else x),
        help_text=
        "Command list (or list of lists, in which case each list of commands will be executed in paralell) to build.",
        example=["cmake .", "make"])
    services = FieldSerializer("array",
                               child=ServicesSerializer(),
                               default=[],
                               help_text="Service list.")
Ejemplo n.º 17
0
class AWSBeanStalkDeploySerializer(YAML2PipelineSerializer):
    region = FieldSerializer("string",
                             default="eu-west-1",
                             help_text="The AWS region where to deploy.")
    stack = FieldSerializer(
        "string",
        default="64bit Amazon Linux 2016.03 v2.1.6 running Docker 1.11.2")
    options = FieldSerializer(
        "path",
        example="path/to/options.txt",
        help_text=
        "AWS Option file as described here: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html"
    )

    def _serialize_(self, commands, tmp_dir, app_name, docker_links, config):
        if not self.has_value():
            return

        for port in config.ports:
            if port.container_port != port.host_port:
                raise DMakeException(
                    "AWS Elastic Beanstalk only supports ports binding which are the same in the container and the host."
                )
        ports = [{
            "ContainerPort": ports.container_port
        } for ports in config.ports]
        volumes = [
            {
                "HostDirectory": volume.host_volume,
                "ContainerDirectory": volume.container_volume
            } for volume in config.volumes if volume.host_volume !=
            "/var/log/deepomatic"  # Cannot specify a volume both in logging and mounting
        ]

        if config.pre_deploy_script  != "" or \
           config.mid_deploy_script  != "" or \
           config.post_deploy_script != "":
            raise DMakeException(
                "Pre/Mid/Post-Deploy scripts for AWS is not supported yet.")
        if len(config.docker_opts) > 0:
            raise DMakeException(
                "Docker options for AWS is not supported yet.")

        # Generate Dockerrun.aws.json
        data = {
            "AWSEBDockerrunVersion": "1",
            # "Authentication": {
            #     "Bucket": "my-bucket",
            #     "Key": "mydockercfg"
            # },
            # "Image": {
            #     "Name": "quay.io/johndoe/private-image",
            #     "Update": "true"
            # },
            "Ports": ports,
            "Volumes": volumes,
            "Logging": "/var/log/deepomatic"
        }
        with open(os.path.join(tmp_dir, "Dockerrun.aws.json"),
                  'w') as dockerrun:
            json.dump(data, dockerrun)

        common.run_shell_command(
            'deepomake_replace_vars %s %s' %
            (self.options, os.path.join(tmp_dir, 'options.txt')))

        append_command(commands,
                       'sh',
                       shell='deepomake_deploy_aws_eb "%s" "%s" "%s" "%s"' %
                       (tmp_dir, app_name, self.region, self.stack))
Ejemplo n.º 18
0
class DockerSerializer(YAML2PipelineSerializer):
    root_image = FieldSerializer([
        FieldSerializer(
            "path",
            help_text=
            "to another deepomake file, in which base the root_image will be this file's base_image."
        ),
        DockerRootImageSerializer()
    ],
                                 help_text="The source image name to build on.",
                                 example="ubuntu:16.04")
    base_image = DockerBaseSerializer(
        optional=True,
        help_text="Base (intermediate) image to speed-up builds.")
    command = FieldSerializer(
        "string",
        default="bash",
        help_text=
        "Only used when running 'dmake shell': set the command of the container"
    )

    def _serialize_(self, commands, path_dir):
        if self.base_image.has_value():
            # Make the temporary directory
            tmp_dir = common.run_shell_command('deepomake_make_tmp_dir')

            # Copy file and compute their md5
            files_to_copy = []
            for file in self.base_image.copy_files + self.base_image.install_scripts:
                files_to_copy.append(file)
            if self.base_image.python_requirements:
                files_to_copy.append(self.base_image.python_requirements)
            if self.base_image.python3_requirements:
                files_to_copy.append(self.base_image.python3_requirements)

            # Copy file and keep their md5
            md5s = {}
            for file in files_to_copy:
                md5s[file] = common.run_shell_command(
                    'deepomake_copy_file %s %s' % (os.path.join(
                        path_dir, file), os.path.join(tmp_dir, 'user', file)))

            # Set RUN command
            run_cmd = "cd user"
            for file in self.base_image.install_scripts:
                run_cmd += " && ./%s" % file

            # Install pip if needed
            if self.base_image.python_requirements:
                run_cmd += " && bash ../install_pip.sh && pip install --process-dependency-links -r " + self.base_image.python_requirements
            if self.base_image.python3_requirements:
                run_cmd += " && bash ../install_pip3.sh && pip3 install --process-dependency-links -r " + self.base_image.python3_requirements

            # Save the command in a bash file
            file = 'run_cmd.sh'
            with open(os.path.join(tmp_dir, file), 'w') as f:
                f.write(run_cmd)
            md5s[file] = common.run_shell_command('deepomake_md5 %s' %
                                                  os.path.join(tmp_dir, file))

            # HACK: copy key while #493 is not closed: https://github.com/docker/for-mac/issues/483
            if common.key_file is not None:
                common.run_shell_command(
                    'cp %s %s' %
                    (common.key_file, os.path.join(tmp_dir, 'key')))

            # Local environment for temmplates
            local_env = []
            local_env.append("export ROOT_IMAGE=%s" % self.root_image)
            local_env = ' && '.join(local_env)
            if len(local_env) > 0:
                local_env += ' && '

            # Copy templates
            for file in [
                    "make_base.sh", "config.logrotate", "load_credentials.sh",
                    "install_pip.sh", "install_pip3.sh"
            ]:
                md5s[file] = common.run_shell_command(
                    '%s deepomake_copy_template docker-base/%s %s' %
                    (local_env, file, os.path.join(tmp_dir, file)))

            # Output md5s for comparison
            with open(os.path.join(tmp_dir, 'md5s'), 'w') as f:
                for md5 in md5s.items():
                    f.write('%s %s\n' % md5)

            # Append Docker Base build command
            append_command(
                commands,
                'sh',
                shell='deepomake_build_base_docker "%s" "%s" "%s" "%s" "%s"' %
                (tmp_dir, self.root_image, self.base_image.name,
                 self._get_tag_(), self.base_image.version))

    def _get_tag_(self):
        if common.is_pr:
            prefix = 'pr-%s' % common.pr_id
        else:
            prefix = common.branch
        return 'base-' + prefix + '-' + self.base_image.version

    def get_docker_base_image_name_tag(self):
        if self.base_image.has_value() is not None:
            image = self.base_image.name + ":" + self._get_tag_()
            return image
        return self.root_image
Ejemplo n.º 19
0
class DeployConfigSerializer(YAML2PipelineSerializer):
    docker_image = ServiceDockerSerializer(
        help_text="Docker to build for running and deploying")
    docker_links_names = FieldSerializer(
        "array",
        child="string",
        default=[],
        example=['mongo'],
        help_text=
        "The docker links names to bind to for this test. Must be declared at the root level of some deepomake file of the app."
    )
    docker_opts = FieldSerializer("string",
                                  default="",
                                  example="--privileged",
                                  help_text="Docker options to add.")
    ports = FieldSerializer("array",
                            child=DeployConfigPortsSerializer(),
                            default=[],
                            help_text="Ports to open.")
    volumes = FieldSerializer("array",
                              child=DeployConfigVolumesSerializer(),
                              default=[],
                              help_text="Volumes to open.")
    pre_deploy_script = FieldSerializer(
        "string",
        default="",
        child_path_only=True,
        example="my/pre_deploy/script",
        help_text="Scripts to run before launching new version.")
    mid_deploy_script = FieldSerializer(
        "string",
        default="",
        child_path_only=True,
        example="my/mid_deploy/script",
        help_text=
        "Scripts to run after launching new version and before stopping the old one."
    )
    post_deploy_script = FieldSerializer(
        "string",
        default="",
        child_path_only=True,
        example="my/post_deploy/script",
        help_text="Scripts to run after stopping old version.")

    def full_docker_opts(self, testing_mode):
        opts = []
        for ports in self.ports:
            opts.append("-p 0.0.0.0:%s:%s" %
                        (ports.host_port, ports.container_port))

        for volumes in self.volumes:
            if testing_mode and not common.is_local:
                host_volume = os.path.join(common.cache_dir, 'volumes',
                                           volumes.host_volume)
                try:
                    os.mkdir(host_volume)
                except OSError:
                    pass

            else:
                host_volume = volumes.host_volume
            opts.append("-v %s:%s" %
                        (common.join_without_slash(host_volume),
                         common.join_without_slash(volumes.container_volume)))

        opts = self.docker_opts + " " + (" ".join(opts))
        return opts
Ejemplo n.º 20
0
class ServiceDockerSerializer(YAML2PipelineSerializer):
    workdir = FieldSerializer(
        "string",
        default="/",
        help_text="Working directory of the produced docker file.")
    install_targets = FieldSerializer(
        "array",
        child=FieldSerializer([
            InstallExeSerializer(),
            InstallLibSerializer(),
            InstallDirSerializer()
        ]),
        default=[],
        help_text="Target files or directories to install.")
    install_script = FieldSerializer(
        "path",
        child_path_only=True,
        executable=True,
        optional=True,
        example="install.sh",
        help_text=
        "The install script (will be run in the docker). It has to be executable."
    )
    entrypoint = FieldSerializer(
        "path",
        optional=True,
        child_path_only=True,
        executable=True,
        help_text=
        "Set the entrypoint of the docker image generated to run the app.")
    start_script = FieldSerializer(
        "path",
        child_path_only=True,
        executable=True,
        example="start.sh",
        help_text=
        "The start script (will be run in the docker). It has to be executable."
    )

    def get_image_name(self, app_name, service_name):
        image_name = "%s-%s:%s" % (app_name, service_name,
                                   common.branch.lower())
        if common.build_id is not None:
            image_name += '.' + common.build_id
        return image_name

    def generate_build(self, commands, path_dir, app_name, service_name,
                       docker_base, env, config):
        tmp_dir = common.run_shell_command('deepomake_make_tmp_dir')

        dockerfile_template = os.path.join(tmp_dir, 'Dockerfile_template')
        with open(dockerfile_template, 'w') as f:
            f.write('FROM %s\n' % docker_base)
            f.write('\n')
            f.write('${ENV_VARS}\n')
            f.write('\n')
            f.write('WORKDIR %s\n' % self.workdir)
            f.write('\n')
            for port in config.ports:
                f.write('EXPOSE %s\n' % port.container_port)
            f.write('\n')
            for target in self.install_targets:
                f.write(target.docker_cmd(commands, path_dir, tmp_dir) + "\n")
            f.write('\n')
            if self.install_script is not None:
                generate_copy_command(commands, path_dir, tmp_dir,
                                      self.install_script)
                f.write('COPY %s %s\n' %
                        (self.install_script,
                         os.path.join(self.workdir, self.install_script)))
                f.write('RUN cd %s && ./%s\n' %
                        (self.workdir, self.install_script))
            f.write('\n')
            generate_copy_command(commands, path_dir, tmp_dir,
                                  self.start_script)
            f.write('COPY %s %s\n' %
                    (self.start_script,
                     os.path.join(self.workdir, self.start_script)))
            if self.entrypoint is not None:
                f.write('ENTRYPOINT ["./%s"]\n' % self.entrypoint)
            f.write('CMD ["./%s"]\n' % self.start_script)

        generate_dockerfile(commands, tmp_dir, env)

        image_name = self.get_image_name(app_name, service_name)
        append_command(commands,
                       'sh',
                       shell='deepomake_build_docker "%s" "%s"' %
                       (tmp_dir, image_name))
        return tmp_dir