# Building a Dockerfile with packages

**URL:** <https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272>\
**Category:** New to Julia\
**Tags:** question, docker\
**Created:** [April 9, 2020, 10:00am UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272 "2020-04-09T10:00:33Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![nnn](https://avatars.discourse-cdn.com/v4/letter/n/58f4c7/32.png) [@nnn](https://discourse.julialang.org/u/nnn)\
**Post date:** [April 9, 2020, 10:00am UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/1 "2020-04-09T10:00:33Z")

</div>

I want to build a docker image with Julia packages ready to go.  
What are best practices for that?

Here’s what I got so far:

```julia
FROM julia

RUN julia install.jl

```

where `install.jl` is:

```julia
using Pkg
packages = ["JSON", "CSV"]
Pkg.add(packages)
using CSV, JSON

```

Is there any way to precompile an array of packages?

[From the docs](https://docs.julialang.org/en/v1.0/stdlib/Pkg/#Pkg.build) I thought that `Pkg.build` accepts array of packages (same as `Pkg.add`) but it throws an error:

```julia
Pkg.build(packages)
ERROR: MethodError: no method matching Pkg.Types.PackageSpec(::Array{String,1})
Closest candidates are:
  Pkg.Types.PackageSpec(::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.4\Pkg\src\Types.jl:91
  Pkg.Types.PackageSpec(; name, uuid, version, tree_hash, repo, path, pinned, mode) at util.jl:742
  Pkg.Types.PackageSpec(::Union{Nothing, String}, ::Union{Nothing, Base.UUID}, ::Union{Pkg.Types.UpgradeLevel, VersionNumber, Pkg.Types.VersionSpec}, ::Union{Nothing, Base.SHA1}, ::Pkg.Types.GitRepo, ::Union{Nothing, String}, ::Bool, ::Pkg.Types.PackageMode) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.4\Pkg\src\Types.jl:91
  ...
Stacktrace:
 [1] iterate at .\generator.jl:47 [inlined]
 [2] collect(::Base.Generator{Tuple{Array{String,1}},Type{Pkg.Types.PackageSpec}}) at .\array.jl:665
 [3] #build#105 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.4\Pkg\src\API.jl:677 [inlined]
 [4] build(::Array{String,1}) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.4\Pkg\src\API.jl:677
 [5] top-level scope at REPL[4]:1

```

Although if I hardcode the array it works:

```julia
Pkg.add(["CSV", "JSON"])

```

But I want to avoid typing modules list twice. How can I do that?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [April 9, 2020, 12:35pm UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/2 "2020-04-09T12:35:31Z")

</div>

You can first `add` all the packages you need, and then run `precompile` - it should precompile all installed packages:

```julia
using Pkg
pkg"add CSV"
pkg"add JSON"
pkg"precompile"

```

At least that’s how I do it.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [April 9, 2020, 2:24pm UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/3 "2020-04-09T14:24:57Z")

</div>

This is also how I do it.

However, for the sake of completeness, I would also like to add another method, which works especially well if you’re starting from a fresh Julia install:

1. prepare your environment on your local machine by manually `Pkg.add`ing all packages you want
2. copy the corresponding `Project.toml` (and possibly the associated Manifest) to `~/.julia/environments/v1.x/` in the Docker file
3. run `pkg"instantiate"` within the docker image to install all packages
4. as mentioned by @aplavin, run `pkg"precompile"` in the docker image to precompile everything

Using a `Project.toml` and `Manifest.toml` instead of a list of `Pkg.add` commands might bring you a few benefits:

- thanks to the manifest, you always get the exact same versions of all packages
- if you use unregistered packages, their url is stored in the manifest (this means that unregistered packages are no special case, whereas the `Pkg.add` invocation for them is a bit more complex than for registered packages)

---

<div class="post-metadata">

**Author:** ![johnh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnh/32/3615_2.png) [@johnh](https://discourse.julialang.org/u/johnh)\
**Post date:** [April 9, 2020, 5:06pm UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/4 "2020-04-09T17:06:01Z")

</div>

This thread might be of interest

> [@Julia packages with Singularity](https://discourse.julialang.org/t/julia-packages-with-singularity/19883/16):
>
> I just encountered the same problems, and I believe I have found a workable solution. First of all, to the command to do the procompilation during build is Base.compilecache, which is a bit particular in that it requires a package identifier as argument, so I found that e.g. Base.compilecache(Base.identify\_package("FileIO")) works to precompile. That being said, for optimal performance the precompilation should probably happen on the system where the container is running, not on the system t…

---

<div class="post-metadata">

**Author:** ![johnh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnh/32/3615_2.png) [@johnh](https://discourse.julialang.org/u/johnh)\
**Post date:** [April 9, 2020, 5:06pm UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/5 "2020-04-09T17:06:20Z")

</div>

Also is this any use to you?

> **[GitHub - JuliaContainerization/SimpleContainerGenerator.jl: Create container...](https://github.com/JuliaContainerization/SimpleContainerGenerator.jl)**
>
> Create container images for using Julia packages (especially useful in environments without Internet access) - GitHub - JuliaContainerization/SimpleContainerGenerator.jl: Create container images fo...

---

<div class="post-metadata">

**Author:** ![benibilme](https://avatars.discourse-cdn.com/v4/letter/b/e5b9ba/32.png) [@benibilme](https://discourse.julialang.org/u/benibilme)\
**Post date:** [October 30, 2021, 12:10am UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/6 "2021-10-30T00:10:16Z")

</div>

This package creates ridiculously long Dockerfile with 2.3gb in size. It even downloads tex live environment. Huge waste of space, besides running all sort of tests… Not seemed practical to me.

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [May 18, 2022, 3:59am UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/7 "2022-05-18T03:59:13Z")

</div>

> [@ffevotte](#):
>
> - copy the corresponding `Project.toml` (and possibly the associated Manifest) to `~/.julia/environments/v1.x/` in the Docker file

Rather than directly copying files into ~/.julia/environments/v1.x/ (and bypassing Pkg) , it may be better to copy \*.toml to a (empty) dir `/foo` and  
execute `julia --project=/foo -e “using Pkg; Pkg.instantiate(); Pkg.precompile()”

---

<div class="post-metadata">

**Author:** ![cswaney](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cswaney/32/29560_2.png) [@cswaney](https://discourse.julialang.org/u/cswaney)\
**Post date:** [May 20, 2022, 3:39pm UTC](https://discourse.julialang.org/t/building-a-dockerfile-with-packages/37272/8 "2022-05-20T15:39:08Z")

</div>

I like @o314’s approach. For completeness, the process is as follows:

1. Create a new Julia environment and add the required packages.

```bash
mkdir Foo
cd Foo && julia -e 'using Pkg; Pkg.activate("."); Pkg.add(["HTTP", "DataFrames"]);'

```

1. Create the Dockerfile

```nohighlight
FROM julia:latest
WORKDIR /env
COPY . . 
RUN julia -e 'using Pkg; Pkg.activate("."); Pkg.instantiate();'

```

1. Remember to activate the environment on the container 🙂

```nohighlight
(@v1.7) pkg> activate env
Julia> using HTTP

```
