JuliaContainerization / Sandbox.jl

The cultured host's toolkit for ill-mannered Linux guests.
Other
35 stars 5 forks source link

Can't install packages with `apk` in the Alpine image #86

Closed giordano closed 2 years ago

giordano commented 2 years ago
julia> using Sandbox

julia> config = SandboxConfig(
           Dict("/" => Sandbox.alpine_rootfs());
           stdin=Base.stdin,
           stdout=Base.stdout,
           stderr=Base.stderr,
       );

julia> with_executor() do exe
           run(exe, config, `/sbin/apk add grep`)
       end
[ Info: Running privileged container via `sudo`, may ask for your password:
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.12/main: temporary error (try again later)
WARNING: Ignoring APKINDEX.2c4ac24e.tar.gz: No such file or directory
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.12/community: temporary error (try again later)
WARNING: Ignoring APKINDEX.40a3604f.tar.gz: No such file or directory
ERROR: unsatisfiable constraints:
  grep (missing):
    required by: world[grep]
ERROR: failed process: Process(setenv(`sudo /home/mose/.julia/artifacts/cc902648a99eecab464d4a99eca4104931591e63/bin/sandbox --rootfs /home/mose/.julia/artifacts/562768a40e93d27b79fbedf9cfa7883409d494ea --cd / --uid 0 --gid 0 -- /sbin/apk add grep`,String[]), ProcessExited(1)) [1]

Stacktrace:
 [1] pipeline_error
   @ ./process.jl:531 [inlined]
 [2] run(::Base.CmdRedirect; wait::Bool)
   @ Base ./process.jl:446
 [3] run
   @ ./process.jl:444 [inlined]
 [4] run(exe::PrivilegedUserNamespacesExecutor, config::SandboxConfig, user_cmd::Cmd; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ Sandbox ~/.julia/dev/Sandbox/src/Sandbox.jl:124
 [5] run
   @ ~/.julia/dev/Sandbox/src/Sandbox.jl:117 [inlined]
 [6] (::var"#1#2")(exe::PrivilegedUserNamespacesExecutor)
   @ Main ./REPL[3]:2
 [7] with_executor(f::var"#1#2", ::Type{PrivilegedUserNamespacesExecutor}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ Sandbox ~/.julia/dev/Sandbox/src/Sandbox.jl:145
 [8] with_executor(f::var"#1#2", ::Type{PrivilegedUserNamespacesExecutor}) (repeats 2 times)
   @ Sandbox ~/.julia/dev/Sandbox/src/Sandbox.jl:143
 [9] top-level scope
   @ REPL[3]:1
giordano commented 2 years ago

Wait, is that because the first mapping is read-only?

giordano commented 2 years ago

Nevermind, the problem wasn't with the read-only layer, but with internet connectivity. Adapting this snippet from the tests https://github.com/staticfloat/Sandbox.jl/blob/f484672e5b5f3aff2e30b56821c18fd3d3e5d581/test/Sandbox.jl#L303-L308 does the trick:

using Sandbox

mktempdir() do rw_dir
    ro_mappings = Dict(
        "/" => Sandbox.alpine_rootfs(),
    )

    # Mount in `/etc/resolv.conf` as a read-only mount if using a UserNS executor, so that we have DNS
    if isfile("/etc/resolv.conf")
        resolv_conf = joinpath(rw_dir, "resolv.conf")
        cp("/etc/resolv.conf", resolv_conf; follow_symlinks=true)
        ro_mappings["/etc/resolv.conf"] = resolv_conf
    end

    config = SandboxConfig(
        ro_mappings;
    )

    with_executor() do exe
        run(exe, config, `/sbin/apk add grep`)
    end
end

For the record, the Debian image ships /etc/resolv.conf by default:

julia> config = SandboxConfig(
           Dict("/" => Sandbox.debian_rootfs());
       );

julia> with_executor() do exe
           run(exe, config, `/usr/bin/cat /etc/resolv.conf`)
       end;
nameserver 1.1.1.1
nameserver 8.8.8.8

so it isn't necessary to copy over our /etc/resolv.conf file to make installation of packages work there.