replicatedhq / dockerfilelint Goto Github PK
View Code? Open in Web Editor NEWAn opinionated Dockerfile linter.
Home Page: https://www.fromlatest.io
License: MIT License
An opinionated Dockerfile linter.
Home Page: https://www.fromlatest.io
License: MIT License
Currently, the linter gives warning of 'First Command Must Be FROM (Possible Bug)'. However, I think there is at least one exception:
In order to have access to build arguments in multiple stages, said build arguments should be declared in the outer scope of the Dockerfile, before any FROM
directives
According to the dockerfile reference documentation:
ARG is the only instruction that may precede FROM in the Dockerfile
With this dockerfile
ARG logstash_version
FROM docker.elastic.co/logstash/logstash:${logstash_version}
I got this error triggered:
dockerfilelint/lib/reference.js
Line 31 in 9b8780c
Regards
For a multistage build, the dockerfilelint
reports the following error
First Command Must Be FROM (Possible Bug)
The first instruction in a Dockerfile must specify the base image using a FROM command. Additionally, FROM cannot appear later in a Dockerfile.
Here is the Dockerfile
I used
https://github.com/onlinejudge95/rinnegan/blob/master/services/server/Dockerfile
FROM scratch
is a special case in docker. It doesn't have any tags and in the build tooling it's a special case to not use an underlying image layer. This tool shouldn't error on a FROM
line with scratch.
I have to disable apt-get-upgrade
and apt-get-dist-upgrade
on every project because those steps are mandatory for installing security updates. The referenced blog post is now gone but the reasoning was always highly suspect for anyone who cares about security since it basically says “don't patch your systems, just get used to ignoring all of those CVEs until you can get an upstream update shipped”. Due to the way layers work, if the upstream is responsive the update will have minimal impact on the image size since all of the relevant packages will already be installed so the only time this has a significant impact is precisely when you need it for security and reliability reasons.
I've got this error message:
˙Line 14 apt-get update without matching apt-get install
All instances of apt-get update should have the apt-get install commands on the same line to reduce image size.
For the following command:
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests \
curl
If I run linter with filename which does not exist it just gives me normal output with 4 issues.
Command:
dockerfilelint NotExistingDockerfile
Output:
File: <contents>
Issues: 4
Line 1: NotExistingDockerfile
Issue Category Title Description
1 Possible Bug Missing Required All commands in a Dockerfile require at least 1 argument.
Arguments A line in a Dockerfile can be in any of the following formats:
* * *
#### `# Comment`
Docker will treat any line that begins with a `#` as a comment.
* * *
#### `INSTRUCTION arguments`
All instructions require at least 1 argument, and should be on the
same line as the `INSTRUCTION`.
* * *
#### `RUN` continuation
If a `RUN` line ends with a `\`, the next line will be treated as
part of the same `RUN` arguement.
* * *
#### Blank or Whitespace
Blank lines are allowed and will be ignored.
* * *
2 Clarity Capitalize For clarity and readability, all instructions in a Dockerfile
Dockerfile should be uppercase.
Instructions This is a convention adopted by most of the official images and
greatly improves readability in long Dockerfiles. For an example
of
why this makes a difference, check out the current [redis
Dockerfile](https://github.com/docker-library/redis/blob/b375650fb6
9b7db819e90c0033433c705b28656e/3.0/Dockerfile)
and you should be able to easily see the instructions used.
3 Possible Bug First Command Must The first instruction in a Dockerfile must specify the base image
Be FROM using a FROM command. Additionally, FROM cannot appear later in a
Dockerfile.
4 Possible Bug Invalid Line This line is not a valid Dockerfile line.
Should linter report internal errors such as it is to stderr
?
Something like File NotExistingDockerfile not found
FROM ruby:2.3-alpine
MAINTAINER 8gears AG <hello.at.8gears.com>
WORKDIR /
COPY . /
EXPOSE 80 443
RUN apk --no-cache add -q -U --virtual build-dependencies \
gcc g++ make musl-dev openssl-dev libffi-dev curl-dev mariadb-dev libxml2-dev zlib-dev libgcrypt-dev libxslt-dev coreutils\
&& apk --no-cache add bash zlib libcurl libxslt tzdata mariadb-libs mariadb-client-libs nodejs\
&& echo 'gem: --verbose --no-document' > /etc/gemrc \
&& gem update --no-document --quiet --system \
&& bundle config build.nokogiri --use-system-libraries \
&& bundle install --jobs=`nproc` --retry=3 --no-cache --clean \
&& rake assets:precompile && rake webpack:compile \
&& apk del --purge build-dependencies ; bash -c "rm -rf /{tmp,root}/{*,.??*}" \
&& rm -rf /usr/lib/ruby/gems/*/cache/* /var/cache/apk/*
COPY . /
ADD . .
CMD ["/start.sh"]
It says I should use --virtual
however I do use it but in the second apk statement the first one is fine as is.
The --no-install-recommends is not found in case something like this is used:
apt-get -y install perl --no-install-recommends
When using the --platform arg to the FROM directive in a Dockerfile, dockerfilelint
errors saying it should specify a tag.
i.e.
Line 7: FROM --platform=$BUILDPLATFORM golang:alpine3.12 as test
Issue Category Title Description
1 Clarity Base Image Missing Base images should specify a tag to use.
Tag
I tested just taking out the --platform=$BUILDPLATFORM
part and it doesn't error any more.
Let me know if you need any more info.
Hello,
The Docker image for this project on the Docker Hub (https://hub.docker.com/r/replicated/dockerfilelint/) is not up to date. In particular, it is missing the .dockerfilelintrc
feature.
Thank you, this is a very cool tool :-)
FROM alpine
USER root node
$ docker run -v `pwd`/Dockerfile:/Dockerfile replicated/dockerfilelint /Dockerfile
File: /Dockerfile
Issues: 2
Line 1: FROM alpine
Issue Category Title Description
1 Clarity Base Image Missing Base images should specify a tag to use.
Tag
Line 2: USER root node
Issue Category Title Description
2 Possible Bug Extra Arguments This command has extra arguments and will be ignored.
$ docker run -it test
docker: Error response from daemon: linux spec user: unable to find user root node: no matching entries in passwd file.
The MAINTAINER
instruction is deprecated:
Consider implementing a warning with suggestion to replace with LABEL maintainer
.
That's one more heuristics to reduce image size, pip
usually places lots of temporary files to /root/.cache
while installing packages.
The following FROM
definitions should all trigger a message:
FROM some.registry:1234/repo/image
FROM some.registry:1234/repo/image as example
FROM repo/image:latest as example
FROM some.registry/repo/image:latest as example
FROM some.registry:1234/repo/image:latest
FROM some.registry:1234/repo/image:latest as example
The presence of the port number for the registry and the use of as
seems to cause the parser to not catch the missing tag or use of latest
.
Add a feature to specify a glob pattern instead of single file as input or directory with recursive search for Dockerfile
s.
I have a project with many dockerfiles in special directory and I want to lint them all, ideally with glob pattern I will do something like this
$ docker run -v `pwd`/docker:/docker replicated/dockerfilelint /docker/**/Dockerfile
or specify a directory like this for search all Dockerfiles inside
$ docker run -v `pwd`/docker:/docker replicated/dockerfilelint /docker/
If sudo is included in a command, dockerfilelint outputs the following message:
Avoid installing or using sudo since it has unpredictable TTY and signal-forwarding behavior that can cause problems. If you absolutely need functionality similar to sudo, such as initializing the daemon as root but running it as non-root), consider using “gosu”.
This message should give more detailed explanations (or a link) on the reasons why sudo should be avoided.
There is also a question about this on unix.stackexchange.com : What exactly in the sudo behavior is unpredictable?
Hopefully some keen person sees this, because this would be very nice to have running in VSCode (rather than installing / running at https://www.fromlatest.io)
In the docker expose instruction one can define what protocol too.
e.g.
EXPOSE 80/tcp 3000/udp
This is currently detected as a non valid port. Definition of the protocol is allowed.
This is maybe fixed by that:
expose_port_valid: function(port) {
return /^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\/tcp|\/udp){0,1}$/.test(port);
},
This also checks for a valid port in range, since currently 99999999 is also detected as a valid port.
Hi,
I was experimenting with linting some dockerfiles and noticed for multi-stage builds the base image we use generally as a builder, does not get linted for the :latest
tag. Is this intentional?
For Example:
FROM golang:latest as builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk add ca-certificates
WORKDIR /root/
copy --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
The second FROM
gets the warning, but the first does not.
Thanks
Is it possible to skip selected "rules"? We have a few rules that we find acceptable, despite not being a best practice and it would be nice to silence those.
I would love to use this project in our Jenkins build pipeline. Having the ability to output JSON would be extremely useful!
As documentation describes, using merged form of ENV directives is preferred over the single form since it will yield smaller intermediate layers and containers.
Hence suggesting changing
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
to
ENV myName="John Doe" \
myDog="Rex The Dog" \
myCat="fluffy"
seems reasonable.
Make dockerfilelint
available as public Docker image!
I think I'm following the instructions, but I'm getting the following error:
$ ./bin/dockerfilelint ../docker/Dockerfile
E:\dockerfilelint\lib\reference.js:4
'description': `All commands in a Dockerfile require at least 1 argument.
^
SyntaxError: Unexpected token ILLEGAL
at exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:443:25)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object.<anonymous> (E:\dockerfilelint\lib\messages.js:2:17)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
Running from Cygwin.
I am trying to use Dockerfilelint programmatically.
dockerfilelint.run()
rereads a config using fs.lstatSync()
and fs.readFileSync()
on every call.
It would be more performant (and in my case more convenient) to be able to pass a config object instead of configPath
to dockerfilelint.run()
:
// I already have `configObject` and `files`
const warnings = files.map(
// Here `dockerfilelint.run()` doesn't read anything from filesystem
(content) => dockerfilelint.run(configObject, content)
);
This should not throw warnings around the LABEL (line4 and 5)
# escape=`
FROM microsoft/nanoserver
SHELL ["powershell.exe", "-C"]
LABEL maintainer="me" `
description="docker container"
Use of the backtick is common in Windows dockerfiles because it aligns with the PowerShell line continuation character.
When the label value contains spaces, the "Label Is Invalid" check breaks down:
File: <stdin>
Issues: 1
Line 41: LABEL build_user_on_behalf_of="Sander\ Verhagen"
Issue Category Title Description
1 Possible Bug Label Is Invalid Using LABEL should be in key=value format.
Gives next warnings dockerfilelint:
15:1 warning dockerfilelint: Clarity Base images should specify a tag to use.
21:1 warning dockerfilelint: Clarity Base images should specify a tag to use.
26:1 warning dockerfilelint: Clarity Base images should specify a tag to use.
Where should I put this tag?
# docker --host=:3000 build -t spa .
# ---- Base image ----
FROM node:alpine AS base
LABEL version="1.0"
LABEL description="HRketing SPA application"
LABEL maintainer="Alex Kostyukov <[email protected]>"
RUN apk --no-cache --update add git
WORKDIR /usr/src/deps
COPY package*.json ./
# ---- Dependencies ----
FROM base AS dependencies
RUN npm set progress=false && npm config set depth 0
RUN npm install --loglevel=error --only=production --prefix node_modules_production
RUN npm install --loglevel=error
# ---- Linters ----
FROM dependencies AS test
COPY . .
RUN npm run lint
# ---- Release ----
FROM base AS release
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV
WORKDIR /usr/src/app
COPY --from=dependencies /usr/src/deps/node_modules_production ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "run", "deploy"]
Introduced in docker-engine 1.12. Documentation at https://docs.docker.com/engine/reference/builder/#healthcheck
If I try to lint this Dockerfile that starts with the followinf two layer declaratio:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS publish
I get a suggestion that the first line should be a FROM. And actually it is.
I think it would be nice to have an issue like that
I'm seeing this with the latest version of dockerfilelint. Running it from the command line or from a container. If I pull a container that's 4 months old I don't see this issue.
./bin/dockerfilelint /Users/cschlit/docker/java/Dockerfile.generated
YError: Invalid first argument. Expected boolean or string but received function.
at argumentTypeError (/Users/cschlit/temp/dockerfilelint/node_modules/yargs/lib/argsert.js:67:9)
at parsed.optional.forEach (/Users/cschlit/temp/dockerfilelint/node_modules/yargs/lib/argsert.js:49:39)
at Array.forEach ()
at argsert (/Users/cschlit/temp/dockerfilelint/node_modules/yargs/lib/argsert.js:44:21)
at Object.version (/Users/cschlit/temp/dockerfilelint/node_modules/yargs/yargs.js:790:5)
at Object. (/Users/cschlit/temp/dockerfilelint/bin/dockerfilelint:21:4)
at Module._compile (internal/modules/cjs/loader.js:722:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
at Module.load (internal/modules/cjs/loader.js:620:32)
at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
File: /Users/cschlit/docker/java/Dockerfile.generated
Issues: None found 👍
Going back to this version (be1f746) on the container on dockerhub - I don't see this issue.
It looks like it's running through the testing correctly, but with that message coming up every time I run it, it looks like it's not working correctly.
The --no-install-recommends
flag info card links to a 404 page.
Hi,
Very cool tool. An improvement: Check for empty continuation lines, since they will become errors in a future release of docker.
This pattern allows us to define a variable and then re-use it in multiple areas in order to keep our Dockerfile DRY. Under the current implementation; dockerfilelint
will state "Invalid Port Exposed"
Somewhat related to #78.
Would it be acceptable to allow for linting stdin somehow? (so this could lint the output of some other tool more easily)
The workarounds I tried failed in pretty amusing ways:
$ echo 'FROM scratch' | dockerfilelint -
File not found
$ echo 'FROM scratch' | dockerfilelint /dev/stdin
Argument should be a file
$ dockerfilelint <(echo 'FROM scratch')
Argument should be a file
According to the package.json file, the project appears to be under the MIT license.
Line 24 in ad65813
I'm not sure if this is accurate or just a copy/paste thing. I think a license file should be added to the root of the Git repository to disambiguate the licensing terms and use of this project and its source code.
As of docker 1.13, the MAINTAINER instruction is deprecated.
The SHELL command was added in docker-engine 1.12 and documentation is at https://docs.docker.com/engine/reference/builder/#shell
I'm getting Line 8: First Command Must Be FROM (Possible Bug)
which is not a problem anymore.
RUN apk update \
&& apk add ca-certificates \
&& rm -rf /var/cache/apk/*
=> "Consider --no-cache
or --update
with rm -rf /var/cache/apk/*
(Optimization)"
The parser should detect the rm -rf …
in the third line.
RUN apk update \
&& rm -rf /var/cache/apk/*
=> No error message.
Most users expect there to be a version cli option for most apps. Dockerfilelint does not have a version cli option so I propose we add one.
I could simply just read the version declared in the package.json
file.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.