skip to Main Content

I am kinda new to Docker containers, so far I have used them, without making my own. Now we have the following scenario. We have one ASP.Net project with Postgres database. That project includes couple of sub-projects and libraries, which are stored in separate repos each. All our repos are in a local git server. We want to be able to develop this project in different OSes and environments, because some of our devs have Windows PCs, while other have Linux. We want everything to be unified and easy for the devs to use – assuming the developer will open VSCode and start the container and everything will work fine. And we want all the code to be inside the container volume – We want to end up with only one .devcontainer folder, which we keep in some git server, then the developer pulls it, opens it in VSCode and all the code and configurations are then pulled and built. First of all, is this possible?

Second – here is what I have tried so far. As I mentioned I added a .devcontainer folder. Inside it I have the following files:
devcontainer.json

// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet-postgres
{
    "name": "My Container",
    "dockerComposeFile": "docker-compose.yml",
    "service": "app",
    "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
    "features": {
        "ghcr.io/devcontainers-contrib/features/apt-get-packages:1": {},
        "ghcr.io/devcontainers-contrib/features/apt-packages:1": {},
        "ghcr.io/devcontainers-contrib/features/bash-command:1": {}
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-dotnettools.vscode-dotnet-runtime"
            ]
        }
    }

    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},

    // Configure tool-specific properties.
    // "customizations": {},

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [5000, 5001, 5432],
    // "portsAttributes": {
    //      "5001": {
    //          "protocol": "https"
    //      }
    // }

    // Use 'postCreateCommand' to run commands after the container is created.
    //"postCreateCommand":
    // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    // "remoteUser": "root"
}

docker-compose.yml

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    
    environment:
      - SSH_AUTH_SOCK=/ssh-agent

    volumes:
      - ../..:/workspaces:cached
      - ${SSH_AUTH_SOCK}:/ssh-agent # Forward local machine SSH key to docker

    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity

    # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
    network_mode: service:db
    
    # Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    # user: root

    # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 
    # (Adding the "ports" property to this file will not forward from a Codespace.)
  db:
    image: postgres:14.3
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres
      
    # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally.
    # (Adding the "ports" property to this file will not forward from a Codespace.)
      
volumes:
  postgres-data:

Dockerfile

FROM mcr.microsoft.com/devcontainers/dotnet:0-7.0

# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive 
    && apt-get -y install --no-install-recommends git

# Set the working directory to /workspace
WORKDIR /workspace

#For the test I am pulling only one repo but in reallity there should be many repos to be pulled.
RUN GIT_TRACE=1 git clone [email protected]:/home/myuser/repos/OneRepo.git

# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

As you can see, I want to pull the code in the Dockerfile (my assumption was that this will pull it inside the devcontainer volume). It starts to pull it but it has issues with the authentication. That is why I tried to forward the ssh-agent, but no luck. Tried to comment out the pull step and the container was started OK but when I open the Docker CLI and run ssh-add -l I am getting authentication error. On my host machine I am able to run that git clone command and pull the code with no issues. I have added the SSH key to the server so I don’t need authentication.

I hope my question was clear enough, but I will provide more details if needed or I have missed something.

Any help is greatly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    @VonC

    Hey, thanks for your answer. I wanted to comment on it, but my comment will be too long so I am posting it as another answer.

    I tried what you suggested but I am still getting the same unauthenticated errors. I added GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -vvv" before the git clone command in order to debug. Below is the whole debug log. The only line that worries me is:

    pubkey_prepare: ssh_get_authentication_socket: No such file or directory
    

    Could it be somehow related to the host machine config? The ssh agent should be working on it, I ran ssh-add -l and it lists correctly all the keys. Or do I need to install something additional on the devcontainer?

    Here is the full log:

    0.389 Cloning ssh://[email protected]:/home/myuser/repos/WebUtilities.git into WebUtilities...
    0.390 Cloning into 'WebUtilities'...
    0.397 OpenSSH_8.4p1 Debian-5+deb11u1, OpenSSL 1.1.1n  15 Mar 2022
    
    0.397 debug1: Reading configuration data /etc/ssh/ssh_config
    
    0.397 debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files
    
    0.397 debug1: /etc/ssh/ssh_config line 21: Applying options for *
    
    0.397 debug2: resolve_canonicalize: hostname 192.168.1.110 is address
    
    0.397 debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/root/.ssh/known_hosts'
    
    0.397 debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/root/.ssh/known_hosts2'
    
    0.397 debug2: ssh_connect_direct
    
    0.397 debug1: Connecting to 192.168.1.110 [192.168.1.110] port 22.
    
    0.402 debug1: Connection established.
    
    0.402 debug1: identity file /root/.ssh/id_rsa type -1
    
    0.402 debug1: identity file /root/.ssh/id_rsa-cert type -1
    
    0.402 debug1: identity file /root/.ssh/id_dsa type -1
    
    0.402 debug1: identity file /root/.ssh/id_dsa-cert type -1
    
    0.402 debug1: identity file /root/.ssh/id_ecdsa type -1
    
    0.402 debug1: identity file /root/.ssh/id_ecdsa-cert type -1
    
    0.402 debug1: identity file /root/.ssh/id_ecdsa_sk type -1
    
    0.402 debug1: identity file /root/.ssh/id_ecdsa_sk-cert type -1
    
    0.402 debug1: identity file /root/.ssh/id_ed25519 type -1
    
    0.402 debug1: identity file /root/.ssh/id_ed25519-cert type -1
    
    0.402 debug1: identity file /root/.ssh/id_ed25519_sk type -1
    
    0.402 debug1: identity file /root/.ssh/id_ed25519_sk-cert type -1
    
    0.403 debug1: identity file /root/.ssh/id_xmss type -1
    
    0.403 debug1: identity file /root/.ssh/id_xmss-cert type -1
    
    0.403 debug1: Local version string SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
    
    0.436 debug1: Remote protocol version 2.0, remote software version OpenSSH_9.2p1 Debian-2+deb12u1
    
    0.436 debug1: match: OpenSSH_9.2p1 Debian-2+deb12u1 pat OpenSSH* compat 0x04000000
    
    0.436 debug2: fd 3 setting O_NONBLOCK
    [2023-12-31T10:19:01.290Z] 0.436 debug1: Authenticating to 192.168.1.110:22 as 'myuser'
    
    0.436 debug3: hostkeys_foreach: reading file "/root/.ssh/known_hosts"
    
    0.436 debug3: record_hostkey: found key type ECDSA in file /root/.ssh/known_hosts:1
    
    0.436 debug3: load_hostkeys: loaded 1 keys from 192.168.1.110
    
    0.436 debug3: order_hostkeyalgs: have matching best-preference key type [email protected], using HostkeyAlgorithms verbatim
    
    0.436 debug3: send packet: type 20
    
    0.436 debug1: SSH2_MSG_KEXINIT sent
    
    0.441 debug3: receive packet: type 20
    
    0.441 debug1: SSH2_MSG_KEXINIT received
    
    0.441 debug2: local client KEXINIT proposal
    
    0.441 debug2: KEX algorithms: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,ext-info-c
    
    0.441 debug2: host key algorithms: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,[email protected],ssh-ed25519,[email protected],rsa-sha2-512,rsa-sha2-256,ssh-rsa
    
    0.441 debug2: ciphers ctos: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
    
    0.441 debug2: ciphers stoc: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
    
    0.441 debug2: MACs ctos: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
    
    0.441 debug2: MACs stoc: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
    
    0.441 debug2: compression ctos: none,[email protected],zlib
    
    0.441 debug2: compression stoc: none,[email protected],zlib
    
    0.441 debug2: languages ctos: 
    
    0.441 debug2: languages stoc: 
    
    0.441 debug2: first_kex_follows 0 
    
    0.441 debug2: reserved 0 
    
    0.441 debug2: peer server KEXINIT proposal
    
    0.441 debug2: KEX algorithms: [email protected],curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
    
    0.441 debug2: host key algorithms: rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256,ssh-ed25519
    
    0.441 debug2: ciphers ctos: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
    
    0.441 debug2: ciphers stoc: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
    
    0.441 debug2: MACs ctos: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
    
    0.441 debug2: MACs stoc: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
    
    0.441 debug2: compression ctos: none,[email protected]
    
    0.441 debug2: compression stoc: none,[email protected]
    
    0.441 debug2: languages ctos: 
    
    0.441 debug2: languages stoc: 
    
    0.441 debug2: first_kex_follows 0 
    
    0.441 debug2: reserved 0 
    
    0.441 debug1: kex: algorithm: curve25519-sha256
    [2023-12-31T10:19:01.290Z] 
    0.441 debug1: kex: host key algorithm: ecdsa-sha2-nistp256
    
    0.442 debug1: kex: server->client cipher: [email protected] MAC: <implicit> compression: none
    
    0.442 debug1: kex: client->server cipher: [email protected] MAC: <implicit> compression: none
    
    0.447 debug3: send packet: type 30
    
    0.447 debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
    
    0.517 debug3: receive packet: type 31
    
    0.517 debug1: Server host key: ecdsa-sha2-nistp256 SHA256:+vI9cGum1pfe6FQYirpYXfjfnA65iZcyS9yI+O+Qrw4
    
    0.517 debug3: hostkeys_foreach: reading file "/root/.ssh/known_hosts"
    
    0.517 debug3: record_hostkey: found key type ECDSA in file /root/.ssh/known_hosts:1
    
    0.517 debug3: load_hostkeys: loaded 1 keys from 192.168.1.110
    
    0.517 debug1: Host '192.168.1.110' is known and matches the ECDSA host key.
    
    0.517 debug1: Found key in /root/.ssh/known_hosts:1
    
    0.521 debug3: send packet: type 21
    
    0.521 debug2: set_newkeys: mode 1
    
    0.521 debug1: rekey out after 134217728 blocks
    
    0.521 debug1: SSH2_MSG_NEWKEYS sent
    
    0.521 debug1: expecting SSH2_MSG_NEWKEYS
    
    0.521 debug3: receive packet: type 21
    
    0.521 debug1: SSH2_MSG_NEWKEYS received
    
    0.521 debug2: set_newkeys: mode 0
    
    0.521 debug1: rekey in after 134217728 blocks
    
    0.521 debug1: pubkey_prepare: ssh_get_authentication_socket: No such file or directory
    
    0.521 debug1: Will attempt key: /root/.ssh/id_rsa 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_dsa 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_ecdsa 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_ecdsa_sk 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_ed25519 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_ed25519_sk 
    
    0.521 debug1: Will attempt key: /root/.ssh/id_xmss 
    
    0.521 debug2: pubkey_prepare: done
    
    0.521 debug3: send packet: type 5
    
    0.521 debug3: receive packet: type 7
    
    0.521 debug1: SSH2_MSG_EXT_INFO received
    
    0.521 debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,[email protected],[email protected],ssh-dss,ssh-rsa,rsa-sha2-256,rsa-sha2-512>
    
    0.521 debug1: kex_input_ext_info: [email protected] (unrecognised)
    
    0.530 debug3: receive packet: type 6
    
    0.530 debug2: service_accept: ssh-userauth
    
    0.530 debug1: SSH2_MSG_SERVICE_ACCEPT received
    
    0.530 debug3: send packet: type 50
    
    0.541 debug3: receive packet: type 51
    
    0.541 debug1: Authentications that can continue: publickey,password
    
    0.541 debug3: start over, passed a different list publickey,password
    
    0.541 debug3: preferred gssapi-with-mic,publickey,keyboard-interactive,password
    
    0.541 debug3: authmethod_lookup publickey
    
    0.541 debug3: remaining preferred: keyboard-interactive,password
    
    0.541 debug3: authmethod_is_enabled publickey
    [2023-12-31T10:19:01.291Z] 
    0.541 debug1: Next authentication method: publickey
    
    0.541 debug1: Trying private key: /root/.ssh/id_rsa
    
    0.541 debug3: no such identity: /root/.ssh/id_rsa: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_dsa
    
    0.541 debug3: no such identity: /root/.ssh/id_dsa: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_ecdsa
    
    0.541 debug3: no such identity: /root/.ssh/id_ecdsa: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_ecdsa_sk
    
    0.541 debug3: no such identity: /root/.ssh/id_ecdsa_sk: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_ed25519
    
    0.541 debug3: no such identity: /root/.ssh/id_ed25519: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_ed25519_sk
    
    0.541 debug3: no such identity: /root/.ssh/id_ed25519_sk: No such file or directory
    
    0.541 debug1: Trying private key: /root/.ssh/id_xmss
    
    0.541 debug3: no such identity: /root/.ssh/id_xmss: No such file or directory
    
    0.541 debug2: we did not send a packet, disable method
    
    0.541 debug3: authmethod_lookup password
    
    0.541 debug3: remaining preferred: ,password
    
    0.541 debug3: authmethod_is_enabled password
    
    0.541 debug1: Next authentication method: password
    
    0.541 debug1: read_passphrase: can't open /dev/tty: No such device or address
    
    0.541 debug3: send packet: type 50
    
    0.541 debug2: we sent a password packet, wait for reply
    
    0.552 debug3: receive packet: type 51
    
    0.552 debug1: Authentications that can continue: publickey,password
    
    0.552 Permission denied, please try again.
    
    0.552 debug1: read_passphrase: can't open /dev/tty: No such device or address
    
    0.552 debug3: send packet: type 50
    
    0.552 debug2: we sent a password packet, wait for reply
    
    0.562 debug3: receive packet: type 51
    
    0.562 debug1: Authentications that can continue: publickey,password
    
    0.562 Permission denied, please try again.
    
    0.562 debug1: read_passphrase: can't open /dev/tty: No such device or address
    
    0.562 debug3: send packet: type 50
    
    0.562 debug2: we sent a password packet, wait for reply
    
    0.573 debug3: receive packet: type 51
    
    0.573 debug1: Authentications that can continue: publickey,password
    [2023-12-31T10:19:01.291Z] 
    0.573 debug2: we did not send a packet, disable method
    
    0.573 debug1: No more authentication methods to try.
    
    0.573 [email protected]: Permission denied (publickey,password).
    
    0.575 fatal: Could not read from remote repository.
    0.575 
    0.575 Please make sure you have the correct access rights
    0.575 and the repository exists.
    

  2. You want a unified development environment across different OSes using Docker. Your environment is an ASP.NET project with a Postgres database, subprojects and libraries in separate repos.
    You need your code and configurations inside a single .devcontainer folder, pulled and built when a developer starts the container in VSCode.

    +-----------------------------------------------------+
    | Host Machine                                        |
    | +-------------------------------------------------+ |
    | | Docker Container (devcontainer)                 | |
    | | +---------------------------------------------+ | |
    | | | VSCode Workspace                            | | |
    | | | +-----------+  +-----------+  +-----------+ | | |
    | | | | Repo 1    |  | Repo 2    |  | Repo N    | | | |
    | | | +-----------+  +-----------+  +-----------+ | | |
    | | +---------------------------------------------+ | |
    | +-------------------------------------------------+ |
    +-----------------------------------------------------+
    

    To pull repos using SSH, the container must have access to SSH keys. Clone each repository within the Dockerfile or a script.

    Your devcontainer.json seems correct. Make sure the SSH_AUTH_SOCK is forwarded correctly (ENV SSH_AUTH_SOCK /ssh-agent in your Dockerfile, which should include an SSH client).

    Modify the Dockerfile to handle SSH keys and clone multiple repositories.

    FROM mcr.microsoft.com/devcontainers/dotnet:0-7.0
    
    # Install git and SSH client
    RUN apt-get update && export DEBIAN_FRONTEND=noninteractive 
        && apt-get -y install --no-install-recommends git ssh-client
    
    # Set the working directory
    WORKDIR /workspace
    
    # Set the SSH_AUTH_SOCK environment variable to the forwarded socket
    ENV SSH_AUTH_SOCK /ssh-agent
    
    # Copy the clone script into the container
    COPY clone-repos.sh /workspace/clone-repos.sh
    
    # Make the script executable
    RUN chmod +x /workspace/clone-repos.sh
    
    # Run the script to clone the repositories
    RUN /workspace/clone-repos.sh
    
    # [Optional] Install global node packages if needed
    # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
    

    With clone-repos.sh (assuming you have a fixed list of repositories to clone):

    #!/bin/bash
    
    # List of repositories to clone
    # Format: "repo-url directory-name"
    REPOS=(
        "ssh://[email protected]:/home/myuser/repos/OneRepo.git one-repo"
        "ssh://[email protected]:/home/myuser/repos/AnotherRepo.git another-repo"
        # Add more repositories here
    )
    
    # Clone each repository
    for repo in "${REPOS[@]}"; do
        read -r url dir <<< "$repo"
        if [ ! -d "$dir" ]; then
            echo "Cloning $url into $dir..."
            git clone "$url" "$dir"
        else
            echo "Directory $dir already exists, skipping clone..."
        fi
    done
    

    For additional ideas, you can refer to h4l/dev-container-docker-compose-volume-or-bind, which also uses a workspace in volume or bind mount.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search