refactor: fix handling of string andd array CMD and ENTRYPOINT values
Previous versions extracted the values as strings, prefixing the values with `/bin/sh -c '$CMD'` unnecessarily. This caused issues where we would incorrectly overrride these values when an app had a predeploy script. Closes #3143
This commit is contained in:
@@ -110,9 +110,7 @@ The following config variables have special meanings and can be set in a variety
|
||||
| `DOKKU_DISABLE_ANSI_PREFIX_REMOVAL` | none | `dokku config:set` <br /> `/etc/environment` <br /> `~dokku/.dokkurc` <br /> `~dokku/.dokkurc/*` | Disables removal of the ANSI prefix during deploys. Can be used in cases where the client deployer does not understand ansi escape codes. |
|
||||
| `DOKKU_DISABLE_APP_AUTOCREATION` | none | `dokku config:set` | Disables automatic creation of a non-existent app on deploy. |
|
||||
| `DOKKU_DOCKER_STOP_TIMEOUT` | `10` | `dokku config:set` | Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands _also_ respect this value. If not specified, the docker defaults for the [docker stop command](https://docs.docker.com/engine/reference/commandline/stop/) will be used.|
|
||||
| `DOKKU_DOCKERFILE_CMD` | dockerfile cmd | `dokku config:set` | |
|
||||
| `DOKKU_DOCKERFILE_CACHE_BUILD` | none | `dokku config:set` | |
|
||||
| `DOKKU_DOCKERFILE_ENTRYPOINT` | dockerfile entrypoint | `dokku config:set` | |
|
||||
| `DOKKU_DOCKERFILE_PORTS` | dockerfile ports | `dokku config:set` | |
|
||||
| `DOKKU_DOCKERFILE_START_CMD` | none | `dokku config:set` | |
|
||||
| `DOKKU_PARALLEL_ARGUMENTS`. | none | `dokku config:set` | Allows passing custom arguments to parallel for `ps:*all` commands |
|
||||
|
||||
@@ -164,7 +164,7 @@ dokku buildpacks:report node-js-app --buildpacks-list
|
||||
If an application was previously deployed via Dockerfile, the following commands should be run before a buildpack deploy will succeed:
|
||||
|
||||
```shell
|
||||
dokku config:unset --no-restart node-js-app DOKKU_DOCKERFILE_CMD DOKKU_DOCKERFILE_ENTRYPOINT DOKKU_PROXY_PORT_MAP
|
||||
dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP
|
||||
```
|
||||
|
||||
### Using a specific buildpack version
|
||||
|
||||
@@ -195,18 +195,12 @@ func executeScript(appName string, imageTag string, phase string) error {
|
||||
|
||||
commitArgs := []string{"container", "commit"}
|
||||
if !isHerokuishImage {
|
||||
dockerfileEntrypoint, _ := common.ConfigGet(appName, "DOKKU_DOCKERFILE_CMD", "")
|
||||
if dockerfileEntrypoint == "" {
|
||||
dockerfileEntrypoint, _ = getEntrypointFromImage(image)
|
||||
}
|
||||
dockerfileEntrypoint, _ := getEntrypointFromImage(image)
|
||||
if dockerfileEntrypoint != "" {
|
||||
commitArgs = append(commitArgs, "--change", dockerfileEntrypoint)
|
||||
}
|
||||
|
||||
dockerfileCommand, _ := common.ConfigGet(appName, "DOKKU_DOCKERFILE_CMD", "")
|
||||
if dockerfileCommand == "" {
|
||||
dockerfileCommand, _ = getCommandFromImage(image)
|
||||
}
|
||||
dockerfileCommand, _ := getCommandFromImage(image)
|
||||
if dockerfileCommand != "" {
|
||||
commitArgs = append(commitArgs, "--change", dockerfileCommand)
|
||||
}
|
||||
@@ -236,21 +230,47 @@ func executeScript(appName string, imageTag string, phase string) error {
|
||||
}
|
||||
|
||||
func getEntrypointFromImage(image string) (string, error) {
|
||||
entrypoint, err := common.DockerInspect(image, "{{range .Config.Entrypoint}}{{.}} {{end}}")
|
||||
output, err := common.DockerInspect(image, "{{json .Config.Entrypoint}}")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if output == "null" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("ENTRYPOINT %s", entrypoint), err
|
||||
var entrypoint []string
|
||||
if err = json.Unmarshal([]byte(output), &entrypoint); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(entrypoint) == 3 && entrypoint[0] == "/bin/sh" && entrypoint[1] == "-c" {
|
||||
return fmt.Sprintf("ENTRYPOINT %s", entrypoint[2]), nil
|
||||
}
|
||||
|
||||
serializedEntrypoint, err := json.Marshal(entrypoint)
|
||||
return fmt.Sprintf("ENTRYPOINT %s", string(serializedEntrypoint)), err
|
||||
}
|
||||
|
||||
func getCommandFromImage(image string) (string, error) {
|
||||
command, err := common.DockerInspect(image, "{{range .Config.Cmd}}{{.}} {{end}}")
|
||||
output, err := common.DockerInspect(image, "{{json .Config.Cmd}}")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if output == "null" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("CMD %s", strings.Replace(command, "/bin/sh -c", "", 1)), err
|
||||
var command []string
|
||||
if err = json.Unmarshal([]byte(output), &command); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(command) == 3 && command[0] == "/bin/sh" && command[1] == "-c" {
|
||||
return fmt.Sprintf("CMD %s", command[2]), nil
|
||||
}
|
||||
|
||||
serializedEntrypoint, err := json.Marshal(command)
|
||||
return fmt.Sprintf("CMD %s", string(serializedEntrypoint)), err
|
||||
}
|
||||
|
||||
func waitForExecution(containerID string) bool {
|
||||
|
||||
@@ -20,12 +20,6 @@ trigger-builder-dockerfile-builder-build() {
|
||||
# extract first port from Dockerfile
|
||||
local DOCKERFILE_PORTS=$(get_dockerfile_exposed_ports Dockerfile)
|
||||
[[ -n "$DOCKERFILE_PORTS" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_PORTS="$DOCKERFILE_PORTS"
|
||||
|
||||
# extract ENTRYPOINT/CMD from Dockerfile
|
||||
local DOCKERFILE_ENTRYPOINT=$(extract_directive_from_dockerfile Dockerfile ENTRYPOINT)
|
||||
[[ -n "$DOCKERFILE_ENTRYPOINT" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_ENTRYPOINT="$DOCKERFILE_ENTRYPOINT"
|
||||
local DOCKERFILE_CMD=$(extract_directive_from_dockerfile Dockerfile CMD)
|
||||
[[ -n "$DOCKERFILE_CMD" ]] && config_set --no-restart "$APP" DOKKU_DOCKERFILE_CMD="$DOCKERFILE_CMD"
|
||||
plugn trigger pre-build-dockerfile "$APP"
|
||||
|
||||
[[ "$DOKKU_DOCKERFILE_CACHE_BUILD" == "false" ]] && DOKKU_DOCKER_BUILD_OPTS="$DOKKU_DOCKER_BUILD_OPTS --no-cache"
|
||||
|
||||
10
tests/apps/dockerfile-entrypoint/Dockerfile
Normal file
10
tests/apps/dockerfile-entrypoint/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM ruby:2.5.1
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
|
||||
ADD Procfile Procfile
|
||||
ADD entrypoint entrypoint
|
||||
ADD app.json app.json
|
||||
|
||||
ENTRYPOINT ["./entrypoint"]
|
||||
1
tests/apps/dockerfile-entrypoint/Procfile
Normal file
1
tests/apps/dockerfile-entrypoint/Procfile
Normal file
@@ -0,0 +1 @@
|
||||
web: sleep 1000
|
||||
7
tests/apps/dockerfile-entrypoint/app.json
Normal file
7
tests/apps/dockerfile-entrypoint/app.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dokku": {
|
||||
"predeploy": "touch /app/predeploy.test"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
tests/apps/dockerfile-entrypoint/entrypoint
Executable file
4
tests/apps/dockerfile-entrypoint/entrypoint
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "entrypoint script started with arguments $@"
|
||||
exec "$@"
|
||||
8
tests/apps/dockerfile-procfile/app.json
Normal file
8
tests/apps/dockerfile-procfile/app.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dokku": {
|
||||
"predeploy": "touch /app/predeploy.test",
|
||||
"postdeploy": "touch /app/postdeploy.test"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,12 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run docker inspect "${TEST_APP}.web.1" --format "{{json .Config.Cmd}}"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output '["/start","web"]'
|
||||
|
||||
run /bin/bash -c "dokku --rm run $TEST_APP ls /app/prebuild.test"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
@@ -37,10 +43,47 @@ teardown() {
|
||||
assert_success
|
||||
}
|
||||
|
||||
|
||||
@test "(app-json) app.json scripts missing" {
|
||||
deploy_app nodejs-express-noappjson
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "(app-json) app.json dockerfile cmd" {
|
||||
deploy_app dockerfile-procfile
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Cmd}}"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output '["/bin/sh","-c","npm start"]'
|
||||
|
||||
run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Entrypoint}}"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output 'null'
|
||||
}
|
||||
|
||||
@test "(app-json) app.json dockerfile entrypoint" {
|
||||
deploy_app dockerfile-entrypoint
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Cmd}}"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output 'null'
|
||||
|
||||
run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Entrypoint}}"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output '["./entrypoint"]'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user