diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ba6ff9f4d8ad5811357fe13c25aacb42dd1e4801..c111767e8c4a814e969fe4eb9c207752be1aafba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -137,6 +137,40 @@ test_with_artifact_dockerfile:
   - cat /folder/testfile
   - test $(cat /folder/testfile) == "testcontent"
 
+# Build image with a symlink
+build_symlinks_dockerfile:
+  <<: *build_test_image
+  variables:
+    TO: ${CI_REGISTRY_IMAGE}/test/symlinks:test_${CI_COMMIT_REF_NAME}
+    CONTEXT_DIR: test/symlinks
+    DOCKER_DEBUG: "true"
+
+test_symlinks_dockerfile:
+  <<: *verify_test_image
+  image: ${CI_REGISTRY_IMAGE}/test/symlinks:test_${CI_COMMIT_REF_NAME}
+  script:
+  - grep -qi alpine /etc/os-release
+  - test $(cat /test/fromsymlink) == "symlink"
+  - test -h /test/fromsymlink
+
+# Build image with a .dockerignore file
+build_dockerignore_dockerfile:
+  <<: *build_test_image
+  variables:
+    TO: ${CI_REGISTRY_IMAGE}/test/dockerignore:test_${CI_COMMIT_REF_NAME}
+    CONTEXT_DIR: test/with_dockerignore
+    DOCKER_DEBUG: "true"
+
+test_dockerignore_dockerfile:
+  <<: *verify_test_image
+  image: ${CI_REGISTRY_IMAGE}/test/dockerignore:test_${CI_COMMIT_REF_NAME}
+  script:
+  - grep -qi alpine /etc/os-release
+  - test -e /test/notignored
+  - test $(cat /test/notignored) == "file"
+  # Verify the file in the .dockerignore file is not present
+  - test ! -e /test/ignored
+
 # If all tests pass and we are running on master, retag the image to latest. This image will be used for user docker builds from now on.
 build_stable_image:
   stage: promote_tested_image_to_latest
diff --git a/docker.go b/docker.go
index bc1619b555e77724a68f1d0d4f2608bbf0177464..c4ccb4c70dffd8c30b26e53529c21d98ce23b8f3 100644
--- a/docker.go
+++ b/docker.go
@@ -1,155 +1,69 @@
 package main
 
 import (
-	"archive/tar"
-	"bytes"
-	"context"
-	"encoding/base64"
-	"encoding/json"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"os"
 	"path"
-	"path/filepath"
 	"strings"
 
+	docker "github.com/fsouza/go-dockerclient"
 	log "github.com/sirupsen/logrus"
-
-	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/client"
-	"github.com/docker/docker/pkg/jsonmessage"
 )
 
 const (
 	flagFile           = "./runonce"
 	dockerDebugEnvName = "DOCKER_DEBUG"
+	dockerSocket       = "unix:///var/run/docker.sock"
 )
 
-func buildImage(options map[string]*string, loginInfo map[string]types.AuthConfig, buildArgs map[string]*string) error {
-	cli, err := client.NewEnvClient()
-	if err != nil {
-		log.Printf("Unable to create docker client: %v", err)
-		return err
-	}
-	defer cli.Close()
+func buildImage(client *docker.Client, options map[string]*string, loginInfo docker.AuthConfigurations, buildArgs []docker.BuildArg) error {
 
 	noCache := options["NO_CACHE"] != nil && *options["NO_CACHE"] == ""
 
-	log.Printf("Preparing local tar file of current dir '%s' for Docker daemon ...", *options["CONTEXT_DIR"])
-	buildOptions := types.ImageBuildOptions{
-		ForceRemove: true,
-		PullParent:  true,
-		Dockerfile:  *options["DOCKER_FILE"],
-		NoCache:     noCache,
-		BuildArgs:   buildArgs,
-		Tags:        []string{*options["TO"]},
-		AuthConfigs: loginInfo,
-	}
-	resp, err := cli.ImageBuild(context.Background(), makeTarReader(*options["CONTEXT_DIR"]), buildOptions)
-	if err != nil {
-		return err
+	buildOptions := docker.BuildImageOptions{
+		Name:       *options["TO"],
+		Dockerfile: *options["DOCKER_FILE"],
+		// Always pull image even if locally accessible. This is absolutely necessary to protect
+		// private source images from being reused if present already.
+		Pull:         true,
+		NoCache:      noCache,
+		BuildArgs:    buildArgs,
+		AuthConfigs:  loginInfo,
+		OutputStream: os.Stdout,
+		ContextDir:   *options["CONTEXT_DIR"],
 	}
-	defer resp.Body.Close()
 
-	err = jsonmessage.DisplayJSONMessagesStream(resp.Body, os.Stdout, 0, true, nil)
-	if err != nil {
+	//	resp, err := cli.ImageBuild(context.Background(), makeTarReader(*options["CONTEXT_DIR"]), buildOptions)
+	if err := client.BuildImage(buildOptions); err != nil {
 		return err
 	}
-
 	return nil
 }
 
-func pushImage(options map[string]*string) error {
-	cli, err := client.NewEnvClient()
+func pushImage(client *docker.Client, options map[string]*string, loginInfo docker.AuthConfigurations) error {
 
-	if err != nil {
-		log.Printf("Unable to create docker client: %v", err)
-		return err
-	}
-	defer cli.Close()
+	// Obtain registry name to pushImage
+	destinationImageFields := strings.Split(*options["TO"], "/")
+	registry := destinationImageFields[0]
 
-	// Prepare login to push the image
-	authObj := map[string]string{
-		"username": *options["DOCKER_LOGIN_USERNAME"],
-		"password": *options["DOCKER_LOGIN_PASSWORD"],
-	}
-	json, err := json.Marshal(authObj)
-	if err != nil {
-		log.Fatal(err)
-	}
-	encodedAuth := base64.StdEncoding.EncodeToString(json)
-
-	pushOptions := types.ImagePushOptions{
-		RegistryAuth: encodedAuth,
+	pushOptions := docker.PushImageOptions{
+		Name:         *options["TO"],
+		Registry:     registry,
+		OutputStream: os.Stdout,
 	}
 
-	resp, err := cli.ImagePush(context.Background(), *options["TO"], pushOptions)
-	if err != nil {
-		return err
+	var authInfo docker.AuthConfiguration
+	if val, ok := loginInfo.Configs[registry]; ok {
+		authInfo = val
+	} else {
+		authInfo = docker.AuthConfiguration{}
 	}
-	defer resp.Close()
+	client.PushImage(pushOptions, authInfo)
 
-	err = jsonmessage.DisplayJSONMessagesStream(resp, os.Stdout, 0, true, nil)
-	if err != nil {
-		return err
-	}
 	return nil
 }
 
-// makeTarReader - Making memory tar for image build context
-// Heavily based on https://github.com/da4nik/ssci/blob/42e0b9c6d93bda94284a2d73343d22dbc9a7e75a/ci/build.go#L48
-func makeTarReader(workdir string) *bytes.Reader {
-	buffer := new(bytes.Buffer)
-
-	tw := tar.NewWriter(buffer)
-	defer tw.Close()
-
-	log.Debug("Preparing to make Tar contents for Docker build")
-	filepath.Walk(workdir, func(file string, fi os.FileInfo, err error) error {
-		// return on any error
-		if err != nil {
-			return err
-		}
-
-		// create a new dir/file header
-		header, err := tar.FileInfoHeader(fi, fi.Name())
-		if err != nil {
-			return err
-		}
-
-		// update the name to correctly reflect the desired destination when untaring
-		header.Name = strings.TrimPrefix(strings.Replace(file, workdir, "", -1), string(filepath.Separator))
-
-		// write the header
-		if err = tw.WriteHeader(header); err != nil {
-			return err
-		}
-
-		// return on directories since there will be no content to tar
-		if fi.Mode().IsDir() {
-			return nil
-		}
-
-		// open files for taring
-		log.Debugf("Adding file %s to Tar contents", file)
-		f, err := os.Open(file)
-		defer f.Close()
-		if err != nil {
-			return err
-		}
-
-		// copy file data into tar writer
-		if _, err := io.Copy(tw, f); err != nil {
-			return err
-		}
-
-		return nil
-	})
-
-	return bytes.NewReader(buffer.Bytes())
-}
-
 // Helper function to convert a string into a pointer of a string
 func getPointer(s string) *string {
 	return &s
@@ -196,17 +110,20 @@ func parseEnvVariables(defaults map[string]*string) map[string]*string {
 }
 
 // Obtain a types.AuthConfig object that can be use to build using a private image
-func loginWithRegistry(username, password, server *string) map[string]types.AuthConfig {
+func loginWithRegistry(username, password, server *string) docker.AuthConfigurations {
 	// If no username and password, ignore auth
-	if username == nil || password == nil || server == nil {
-		return nil
+	authConfigs := docker.AuthConfigurations{
+		Configs: make(map[string]docker.AuthConfiguration),
 	}
-	loginInfo := make(map[string]types.AuthConfig)
-	loginInfo[*server] = types.AuthConfig{
-		Username: *username,
-		Password: *password,
+
+	// If no username and password, ignore auth
+	if !(username == nil || password == nil || server == nil) {
+		authConfigs.Configs[*server] = docker.AuthConfiguration{
+			Username: *username,
+			Password: *password,
+		}
 	}
-	return loginInfo
+	return authConfigs
 }
 
 //Prints useful information for the build
@@ -255,9 +172,9 @@ func overrideFrom(dockerfile, newFrom *string) error {
 }
 
 // Obtain build args from environment variables starting with 'BUILD_ARG'
-func parseBuildArgs() (map[string]*string, error) {
+func parseBuildArgs() ([]docker.BuildArg, error) {
 
-	buildArgs := make(map[string]*string)
+	buildArgs := make([]docker.BuildArg, 0)
 	// os.Environ returns a copy of strings representing the environment,
 	// in the form "key=value".
 	for _, env := range os.Environ() {
@@ -266,7 +183,10 @@ func parseBuildArgs() (map[string]*string, error) {
 			if len(comps) != 3 {
 				return buildArgs, fmt.Errorf("Build arg '%s' is malformed. The value should be a key value pair", env)
 			}
-			buildArgs[comps[1]] = &comps[2]
+			buildArgs = append(buildArgs, docker.BuildArg{
+				Name:  comps[1],
+				Value: comps[2],
+			})
 		}
 	}
 	return buildArgs, nil
@@ -313,8 +233,16 @@ func main() {
 		log.Fatal(err)
 	}
 
+	// Allow users to override the docker host via DOCKER_HOST environment variable
+	// This would allow to work with DinD in a service container for instance
+	dockerHost := dockerSocket
+	if env, present := os.LookupEnv("DOCKER_HOST"); present {
+		dockerHost = env
+	}
+	client, err := docker.NewClient(dockerHost)
+
 	// Proceed to build the image
-	if err := buildImage(options, loginInfo, buildArgs); err != nil {
+	if err := buildImage(client, options, loginInfo, buildArgs); err != nil {
 		log.Fatal(err)
 	}
 	log.Println("Build successfully completed!")
@@ -322,7 +250,7 @@ func main() {
 	// If all good building the image, push it to the registry
 	if options["TO"] != nil {
 		log.Printf("Pushing the built image to '%s'", *options["TO"])
-		if err := pushImage(options); err != nil {
+		if err := pushImage(client, options, loginInfo); err != nil {
 			log.Fatal(err)
 		}
 		log.Printf("Image successfully pushed to '%s'", *options["TO"])
diff --git a/test/symlinks/Dockerfile b/test/symlinks/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..a3d2aa8eae6b22d321ae7b0ecbc4ffab10e129dd
--- /dev/null
+++ b/test/symlinks/Dockerfile
@@ -0,0 +1,3 @@
+FROM alpine:latest
+
+COPY . /test
diff --git a/test/symlinks/dest/testsymlink b/test/symlinks/dest/testsymlink
new file mode 100644
index 0000000000000000000000000000000000000000..d933faa92d675020afeefd69de4580a0badead21
--- /dev/null
+++ b/test/symlinks/dest/testsymlink
@@ -0,0 +1 @@
+symlink
diff --git a/test/symlinks/fromsymlink b/test/symlinks/fromsymlink
new file mode 120000
index 0000000000000000000000000000000000000000..f6ea8d4570048353523ff7dfe80af5d9b351fbde
--- /dev/null
+++ b/test/symlinks/fromsymlink
@@ -0,0 +1 @@
+dest/testsymlink
\ No newline at end of file
diff --git a/test/with_dockerignore/.dockerignore b/test/with_dockerignore/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..8485e986e458a566e6f6160f71d704edc10c57fc
--- /dev/null
+++ b/test/with_dockerignore/.dockerignore
@@ -0,0 +1 @@
+ignore
\ No newline at end of file
diff --git a/test/with_dockerignore/Dockerfile b/test/with_dockerignore/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..a3d2aa8eae6b22d321ae7b0ecbc4ffab10e129dd
--- /dev/null
+++ b/test/with_dockerignore/Dockerfile
@@ -0,0 +1,3 @@
+FROM alpine:latest
+
+COPY . /test
diff --git a/test/with_dockerignore/ignore b/test/with_dockerignore/ignore
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/test/with_dockerignore/notignored b/test/with_dockerignore/notignored
new file mode 100644
index 0000000000000000000000000000000000000000..1a010b1c0f081b2e8901d55307a15c29ff30af0e
--- /dev/null
+++ b/test/with_dockerignore/notignored
@@ -0,0 +1 @@
+file
\ No newline at end of file