{"id":39985921,"url":"https://github.com/davetang/learning_docker","last_synced_at":"2026-01-18T23:39:43.627Z","repository":{"id":45176284,"uuid":"56837741","full_name":"davetang/learning_docker","owner":"davetang","description":"Learning about Docker.","archived":false,"fork":false,"pushed_at":"2025-10-10T02:44:41.000Z","size":11156,"stargazers_count":61,"open_issues_count":1,"forks_count":18,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-12T06:09:19.891Z","etag":null,"topics":["docker"],"latest_commit_sha":null,"homepage":"http://davetang.github.io/learning_docker/","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davetang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-04-22T08:01:41.000Z","updated_at":"2025-10-10T02:44:44.000Z","dependencies_parsed_at":"2023-01-31T02:15:45.373Z","dependency_job_id":"d15f6e42-f1b7-4d3d-9561-887b8f2a8edf","html_url":"https://github.com/davetang/learning_docker","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/davetang/learning_docker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davetang%2Flearning_docker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davetang%2Flearning_docker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davetang%2Flearning_docker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davetang%2Flearning_docker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davetang","download_url":"https://codeload.github.com/davetang/learning_docker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davetang%2Flearning_docker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28553718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T23:36:08.491Z","status":"ssl_error","status_checked_at":"2026-01-18T23:33:54.990Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker"],"created_at":"2026-01-18T23:39:42.920Z","updated_at":"2026-01-18T23:39:43.616Z","avatar_url":"https://github.com/davetang.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nTable of Contents\n=================\n\n* [Learning Docker](#learning-docker)\n   * [Introduction](#introduction)\n   * [Installing the Docker Engine](#installing-the-docker-engine)\n   * [Checking your installation](#checking-your-installation)\n   * [Docker information](#docker-information)\n   * [Basics](#basics)\n   * [Start containers automatically](#start-containers-automatically)\n   * [Dockerfile](#dockerfile)\n      * [ARG](#arg)\n      * [CMD](#cmd)\n      * [COPY](#copy)\n      * [ENTRYPOINT](#entrypoint)\n   * [Building an image](#building-an-image)\n   * [Renaming an image](#renaming-an-image)\n   * [Running an image](#running-an-image)\n   * [Setting environment variables](#setting-environment-variables)\n   * [Resource usage](#resource-usage)\n   * [Copying files between host and container](#copying-files-between-host-and-container)\n   * [Sharing between host and container](#sharing-between-host-and-container)\n      * [File permissions](#file-permissions)\n      * [File Permissions 2](#file-permissions-2)\n      * [Read only](#read-only)\n   * [Removing the image](#removing-the-image)\n   * [Committing changes](#committing-changes)\n   * [Access running container](#access-running-container)\n   * [Cleaning up exited containers](#cleaning-up-exited-containers)\n   * [Installing Perl modules](#installing-perl-modules)\n   * [Creating a data container](#creating-a-data-container)\n   * [R](#r)\n   * [Saving and transferring a Docker image](#saving-and-transferring-a-docker-image)\n   * [Sharing your image](#sharing-your-image)\n      * [Docker Hub](#docker-hub)\n      * [Quay.io](#quayio)\n      * [GitHub Actions](#github-actions)\n   * [Tips](#tips)\n   * [Useful links](#useful-links)\n\n\u003c!-- Created by https://github.com/ekalinin/github-markdown-toc --\u003e\n\nSat Sep 20 02:57:44 UTC 2025\n\nLearning Docker\n================\n\n## Introduction\n\n![](https://github.com/davetang/learning_docker/actions/workflows/create_readme.yml/badge.svg)\n\nDocker is an open source project that allows one to pack, ship, and run\nany application as a lightweight container. An analogy of Docker\ncontainers are shipping containers, which provide a standard and\nconsistent way of shipping just about anything. The container includes\neverything that is needed for an application to run including the code,\nsystem tools, and the necessary dependencies. If you wanted to test an\napplication, all you need to do is to download the Docker image and run\nit in a new container. No more compiling and installing missing\ndependencies!\n\nThe [overview](https://docs.docker.com/get-started/overview/) at\n\u003chttps://docs.docker.com/\u003e provides more information. For more a more\nhands-on approach, check out know [Enough Docker to be\nDangerous](https://docs.docker.com/) and [this short\nworkshop](https://davetang.github.io/reproducible_bioinformatics/docker.html)\nthat I prepared for BioC Asia 2019.\n\nThis README was generated by GitHub Actions using the R Markdown file\n`readme.Rmd`, which was executed via the `create_readme.sh` script.\n\n## Installing the Docker Engine\n\nTo get started, you will need to install the Docker Engine; check out\n[this guide](https://docs.docker.com/engine/install/).\n\n## Checking your installation\n\nTo see if everything is working, try to obtain the Docker version.\n\n``` bash\ndocker --version\n```\n\n    ## Docker version 28.0.4, build b8034c0\n\nAnd run the `hello-world` image. (The `--rm` parameter is used to\nautomatically remove the container when it exits.)\n\n``` bash\ndocker run --rm hello-world\n```\n\n    ## Unable to find image 'hello-world:latest' locally\n    ## latest: Pulling from library/hello-world\n    ## 17eec7bbc9d7: Pulling fs layer\n    ## 17eec7bbc9d7: Download complete\n    ## 17eec7bbc9d7: Pull complete\n    ## Digest: sha256:54e66cc1dd1fcb1c3c58bd8017914dbed8701e2d8c74d9262e26bd9cc1642d31\n    ## Status: Downloaded newer image for hello-world:latest\n    ## \n    ## Hello from Docker!\n    ## This message shows that your installation appears to be working correctly.\n    ## \n    ## To generate this message, Docker took the following steps:\n    ##  1. The Docker client contacted the Docker daemon.\n    ##  2. The Docker daemon pulled the \"hello-world\" image from the Docker Hub.\n    ##     (amd64)\n    ##  3. The Docker daemon created a new container from that image which runs the\n    ##     executable that produces the output you are currently reading.\n    ##  4. The Docker daemon streamed that output to the Docker client, which sent it\n    ##     to your terminal.\n    ## \n    ## To try something more ambitious, you can run an Ubuntu container with:\n    ##  $ docker run -it ubuntu bash\n    ## \n    ## Share images, automate workflows, and more with a free Docker ID:\n    ##  https://hub.docker.com/\n    ## \n    ## For more examples and ideas, visit:\n    ##  https://docs.docker.com/get-started/\n\n## Docker information\n\nGet more version information.\n\n``` bash\ndocker version\n```\n\n    ## Client: Docker Engine - Community\n    ##  Version:           28.0.4\n    ##  API version:       1.48\n    ##  Go version:        go1.23.7\n    ##  Git commit:        b8034c0\n    ##  Built:             Tue Mar 25 15:07:16 2025\n    ##  OS/Arch:           linux/amd64\n    ##  Context:           default\n    ## \n    ## Server: Docker Engine - Community\n    ##  Engine:\n    ##   Version:          28.0.4\n    ##   API version:      1.48 (minimum version 1.24)\n    ##   Go version:       go1.23.7\n    ##   Git commit:       6430e49\n    ##   Built:            Tue Mar 25 15:07:16 2025\n    ##   OS/Arch:          linux/amd64\n    ##   Experimental:     false\n    ##  containerd:\n    ##   Version:          1.7.27\n    ##   GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da\n    ##  runc:\n    ##   Version:          1.2.5\n    ##   GitCommit:        v1.2.5-0-g59923ef\n    ##  docker-init:\n    ##   Version:          0.19.0\n    ##   GitCommit:        de40ad0\n\nEven more information.\n\n``` bash\ndocker info\n```\n\n    ## Client: Docker Engine - Community\n    ##  Version:    28.0.4\n    ##  Context:    default\n    ##  Debug Mode: false\n    ##  Plugins:\n    ##   buildx: Docker Buildx (Docker Inc.)\n    ##     Version:  v0.28.0\n    ##     Path:     /usr/libexec/docker/cli-plugins/docker-buildx\n    ##   compose: Docker Compose (Docker Inc.)\n    ##     Version:  v2.38.2\n    ##     Path:     /usr/libexec/docker/cli-plugins/docker-compose\n    ## \n    ## Server:\n    ##  Containers: 0\n    ##   Running: 0\n    ##   Paused: 0\n    ##   Stopped: 0\n    ##  Images: 1\n    ##  Server Version: 28.0.4\n    ##  Storage Driver: overlay2\n    ##   Backing Filesystem: extfs\n    ##   Supports d_type: true\n    ##   Using metacopy: false\n    ##   Native Overlay Diff: false\n    ##   userxattr: false\n    ##  Logging Driver: json-file\n    ##  Cgroup Driver: systemd\n    ##  Cgroup Version: 2\n    ##  Plugins:\n    ##   Volume: local\n    ##   Network: bridge host ipvlan macvlan null overlay\n    ##   Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog\n    ##  Swarm: inactive\n    ##  Runtimes: io.containerd.runc.v2 runc\n    ##  Default Runtime: runc\n    ##  Init Binary: docker-init\n    ##  containerd version: 05044ec0a9a75232cad458027ca83437aae3f4da\n    ##  runc version: v1.2.5-0-g59923ef\n    ##  init version: de40ad0\n    ##  Security Options:\n    ##   apparmor\n    ##   seccomp\n    ##    Profile: builtin\n    ##   cgroupns\n    ##  Kernel Version: 6.11.0-1018-azure\n    ##  Operating System: Ubuntu 24.04.3 LTS\n    ##  OSType: linux\n    ##  Architecture: x86_64\n    ##  CPUs: 4\n    ##  Total Memory: 15.62GiB\n    ##  Name: runnervmf4ws1\n    ##  ID: 80b0c887-f378-498c-94b8-5e260688697c\n    ##  Docker Root Dir: /var/lib/docker\n    ##  Debug Mode: false\n    ##  Username: githubactions\n    ##  Experimental: false\n    ##  Insecure Registries:\n    ##   ::1/128\n    ##   127.0.0.0/8\n    ##  Live Restore Enabled: false\n\n## Basics\n\nThe two guides linked in the introduction section provide some\ninformation on the basic commands but I’ll include some here as well.\nOne of the main reasons I use Docker is for building tools. For this\npurpose, I use Docker like a virtual machine, where I can install\nwhatever I want. This is important because I can do my testing in an\nisolated environment and not worry about affecting the main server. I\nlike to use Ubuntu because it’s a popular Linux distribution and\ntherefore whenever I run into a problem, chances are higher that someone\nelse has had the same problem, asked a question on a forum, and received\na solution.\n\nBefore we can run Ubuntu using Docker, we need an image. We can obtain\nan Ubuntu image from the [official Ubuntu image\nrepository](https://hub.docker.com/_/ubuntu/) from Docker Hub by running\n`docker pull`.\n\n``` bash\ndocker pull ubuntu:18.04\n```\n\n    ## 18.04: Pulling from library/ubuntu\n    ## 7c457f213c76: Pulling fs layer\n    ## 7c457f213c76: Verifying Checksum\n    ## 7c457f213c76: Download complete\n    ## 7c457f213c76: Pull complete\n    ## Digest: sha256:152dc042452c496007f07ca9127571cb9c29697f42acbfad72324b2bb2e43c98\n    ## Status: Downloaded newer image for ubuntu:18.04\n    ## docker.io/library/ubuntu:18.04\n\nTo run Ubuntu using Docker, we use `docker run`.\n\n``` bash\ndocker run --rm ubuntu:18.04 cat /etc/os-release\n```\n\n    ## NAME=\"Ubuntu\"\n    ## VERSION=\"18.04.6 LTS (Bionic Beaver)\"\n    ## ID=ubuntu\n    ## ID_LIKE=debian\n    ## PRETTY_NAME=\"Ubuntu 18.04.6 LTS\"\n    ## VERSION_ID=\"18.04\"\n    ## HOME_URL=\"https://www.ubuntu.com/\"\n    ## SUPPORT_URL=\"https://help.ubuntu.com/\"\n    ## BUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\n    ## PRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\n    ## VERSION_CODENAME=bionic\n    ## UBUNTU_CODENAME=bionic\n\nYou can work interactively with the Ubuntu image by specifying the `-it`\noption.\n\n``` console\ndocker run --rm -it ubuntu:18:04 /bin/bash\n```\n\nYou may have noticed that I keep using the `--rm` option, which removes\nthe container once you quit. If you don’t use this option, the container\nis saved up until the point that you exit; all changes you made, files\nyou created, etc. are saved. Why am I deleting all my changes? Because\nthere is a better (and more reproducible) way to make changes to the\nsystem and that is by using a Dockerfile.\n\n## Start containers automatically\n\nWhen hosting a service using Docker (such as running [RStudio\nServer](https://davetang.org/muse/2021/04/24/running-rstudio-server-with-docker/https://davetang.org/muse/2021/04/24/running-rstudio-server-with-docker/)),\nit would be nice if the container automatically starts up again when the\nserver (and Docker) restarts. If you use `--restart flag` with\n`docker run`, Docker will [restart your\ncontainer](https://docs.docker.com/config/containers/start-containers-automatically/)\nwhen your container has exited or when Docker restarts. The value of the\n`--restart` flag can be the following:\n\n- `no` - do not automatically restart (default)\n- `on-failure[:max-retries]` - restarts if it exits due to an error\n  (non-zero exit code) and the number of attempts is limited using the\n  `max-retries` option\n- `always` - always restarts the container; if it is manually stopped,\n  it is restarted only when the Docker daemon restarts (or when the\n  container is manually restarted)\n- `unless-stopped` - similar to `always` but when the container is\n  stopped, it is not restarted even after the Docker daemon restarts.\n\n``` console\ndocker run -d \\\n   --restart always \\\n   -p 8888:8787 \\\n   -e PASSWORD=password \\\n   -e USERID=$(id -u) \\\n   -e GROUPID=$(id -g) \\\n   rocker/rstudio:4.1.2\n```\n\n## Dockerfile\n\nA Dockerfile is a text file that contains instructions for building\nDocker images. A Dockerfile adheres to a specific format and set of\ninstructions, which you can find at [Dockerfile\nreference](https://docs.docker.com/engine/reference/builder/). There is\nalso a [Best practices\nguide](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)\nfor writing Dockerfiles.\n\nA Docker image is made up of different layers and they act like\nsnapshots. Each layer, or intermediate image, is created each time an\ninstruction in the Dockerfile is executed. Each layer is assigned a\nunique hash and are cached by default. This means that you do not need\nto rebuild a layer again from scratch if it has not changed. Keep this\nin mind when creating a Dockerfile.\n\nSome commonly used instructions include:\n\n- `FROM` - Specifies the parent or base image to use for building an\n  image and must be the first command in the file.\n- `COPY` - Copies files from the current directory (of where the\n  Dockerfile is) to the image filesystem.\n- `RUN` - Executes a command inside the image.\n- `ADD` - Adds new files or directories from a source or URL to the\n  image filesystem.\n- `ENTRYPOINT` - Makes the container run like an executable.\n- `CMD` - The default command or parameter/s for the container and can\n  be used with `ENTRYPOINT`.\n- `WORKDIR` - Sets the working directory for the image. Any `CMD`,\n  `RUN`, `COPY`, or `ENTRYPOINT` instruction after the `WORKDIR`\n  declaration will be executed in the context of the working directory.\n- `USER` - Changes the user\n\nI have an example Dockerfile that uses the Ubuntu 18.04 image to build\n[BWA](https://github.com/lh3/bwa), a popular short read alignment tool\nused in bioinformatics.\n\n``` bash\ncat Dockerfile\n```\n\n    ## FROM ubuntu:18.04\n    ## \n    ## MAINTAINER Dave Tang \u003cme@davetang.org\u003e\n    ## \n    ## LABEL source=\"https://github.com/davetang/learning_docker/blob/main/Dockerfile\"\n    ## \n    ## RUN apt-get clean all \u0026\u0026 \\\n    ##     apt-get update \u0026\u0026 \\\n    ##     apt-get upgrade -y \u0026\u0026 \\\n    ##     apt-get install -y \\\n    ##      build-essential \\\n    ##      wget \\\n    ##      zlib1g-dev \u0026\u0026 \\\n    ##     apt-get clean all \u0026\u0026 \\\n    ##     apt-get purge \u0026\u0026 \\\n    ##     rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*\n    ## \n    ## RUN mkdir /src \u0026\u0026 \\\n    ##     cd /src \u0026\u0026 \\\n    ##     wget https://github.com/lh3/bwa/releases/download/v0.7.17/bwa-0.7.17.tar.bz2 \u0026\u0026 \\\n    ##     tar xjf bwa-0.7.17.tar.bz2 \u0026\u0026 \\\n    ##     cd bwa-0.7.17 \u0026\u0026 \\\n    ##     make \u0026\u0026 \\\n    ##     mv bwa /usr/local/bin \u0026\u0026 \\\n    ##     cd \u0026\u0026 rm -rf /src\n    ## \n    ## WORKDIR /work\n    ## \n    ## CMD [\"bwa\"]\n\n### ARG\n\nTo define variables in your Dockerfile use `ARG name=value`. For\nexample, you can use `ARG` to create a new variable that stores a\nversion number of a program. When a new version of the program is\nreleased, you can simply change the `ARG` and re-build your Dockerfile.\n\n    ARG star_ver=2.7.10a\n    RUN cd /usr/src \u0026\u0026 \\\n        wget https://github.com/alexdobin/STAR/archive/refs/tags/${star_ver}.tar.gz \u0026\u0026 \\\n        tar xzf ${star_ver}.tar.gz \u0026\u0026 \\\n        rm ${star_ver}.tar.gz \u0026\u0026 \\\n        cd STAR-${star_ver}/source \u0026\u0026 \\\n        make STAR \u0026\u0026 \\\n        cd /usr/local/bin \u0026\u0026 \\\n        ln -s /usr/src/STAR-${star_ver}/source/STAR .\n\n### CMD\n\nThe [CMD](https://docs.docker.com/engine/reference/builder/#cmd)\ninstruction in a Dockerfile does not execute anything at build time but\nspecifies the intended command for the image; there can only be one CMD\ninstruction in a Dockerfile and if you list more than one CMD then only\nthe last CMD will take effect. The main purpose of a CMD is to provide\ndefaults for an executing container.\n\n### COPY\n\nThe [COPY](https://docs.docker.com/engine/reference/builder/#copy)\ninstruction copies new files or directories from `\u003csrc\u003e` and adds them\nto the filesystem of the container at the path `\u003cdest\u003e`. It has two\nforms:\n\n    COPY [--chown=\u003cuser\u003e:\u003cgroup\u003e] [--chmod=\u003cperms\u003e] \u003csrc\u003e... \u003cdest\u003e\n    COPY [--chown=\u003cuser\u003e:\u003cgroup\u003e] [--chmod=\u003cperms\u003e] [\"\u003csrc\u003e\",... \"\u003cdest\u003e\"]\n\nNote the `--chown` parameter, which can be used to set the ownership of\nthe copied files/directories. If this is not specified, the default\nownership is `root`, which can be a problem.\n\nFor example in the RStudio Server\n[Dockerfile](https://github.com/davetang/learning_docker/blob/main/rstudio/Dockerfile),\nthere are two `COPY` instructions that set the ownership to the\n`rstudio` user.\n\n    COPY --chown=rstudio:rstudio rstudio/rstudio-prefs.json /home/rstudio/.config/rstudio\n    COPY --chown=rstudio:rstudio rstudio/.Rprofile /home/rstudio/\n\nThe two files that are copied are config files and therefore need to be\nwritable by `rstudio` if settings are changed in RStudio Server.\n\nUsually the root path of `\u003csrc\u003e` is set to the directory where the\nDockerfile exists. The example above is different because the RStudio\nServer image is built by GitHub Actions, and the root path of `\u003csrc\u003e` is\nthe GitHub repository.\n\n### ENTRYPOINT\n\nAn\n[ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint)\nallows you to configure a container that will run as an executable.\nENTRYPOINT has two forms:\n\n- ENTRYPOINT \\[“executable”, “param1”, “param2”\\] (exec form, preferred)\n- ENTRYPOINT command param1 param2 (shell form)\n\n``` console\nFROM ubuntu\nENTRYPOINT [\"top\", \"-b\"]\nCMD [\"-c\"]\n```\n\nUse `--entrypoint` to override ENTRYPOINT instruction.\n\n``` console\ndocker run --entrypoint\n```\n\n## Building an image\n\nUse the `build` subcommand to build Docker images and use the `-f`\nparameter if your Dockerfile is named as something else otherwise Docker\nwill look for a file named `Dockerfile`. The period at the end, tells\nDocker to look in the current directory.\n\n``` bash\ncat build.sh\n```\n\n    ## #!/usr/bin/env bash\n    ## \n    ## set -euo pipefail\n    ## \n    ## ver=0.7.17\n    ## \n    ## docker build -t davetang/bwa:${ver} .\n\nYou can push the built image to [Docker Hub](https://hub.docker.com/) if\nyou have an account. I have used my Docker Hub account name to name my\nDocker image.\n\n``` console\n# use -f to specify the Dockerfile to use\n# the period indicates that the Dockerfile is in the current directory\ndocker build -f Dockerfile.base -t davetang/base .\n\n# log into Docker Hub\ndocker login\n\n# push to Docker Hub\ndocker push davetang/base\n```\n\n## Renaming an image\n\nThe `docker image tag` command will create a new tag, i.e. new image\nname, that refers to an old image. It is not quite renaming but can be\nconsidered renaming since you will have a new name for your image.\n\nThe usage is:\n\n    Usage:  docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]\n\nFor example I have created a new tag for my RStudio Server image, so\nthat I can easily push it to Quay.io.\n\n``` console\ndocker image tag davetang/rstudio:4.2.2 quay.io/davetang31/rstudio:4.2.2\n```\n\nThe original image `davetang/rstudio:4.2.2` still exists, which is why\ntagging is not quite renaming.\n\n## Running an image\n\n[Docker run\ndocumentation](https://docs.docker.com/engine/reference/run/).\n\n``` bash\ndocker run --rm davetang/bwa:0.7.17\n```\n\n    ## Unable to find image 'davetang/bwa:0.7.17' locally\n    ## 0.7.17: Pulling from davetang/bwa\n    ## feac53061382: Pulling fs layer\n    ## 549f86662946: Pulling fs layer\n    ## 5f22362f8660: Pulling fs layer\n    ## 3836f06c7ac7: Pulling fs layer\n    ## 3836f06c7ac7: Waiting\n    ## feac53061382: Verifying Checksum\n    ## feac53061382: Download complete\n    ## 5f22362f8660: Verifying Checksum\n    ## 5f22362f8660: Download complete\n    ## 3836f06c7ac7: Download complete\n    ## feac53061382: Pull complete\n    ## 549f86662946: Verifying Checksum\n    ## 549f86662946: Download complete\n    ## 549f86662946: Pull complete\n    ## 5f22362f8660: Pull complete\n    ## 3836f06c7ac7: Pull complete\n    ## Digest: sha256:f0da4e206f549ed8c08f5558b111cb45677c4de6a3dc0f2f0569c648e8b27fc5\n    ## Status: Downloaded newer image for davetang/bwa:0.7.17\n    ## \n    ## Program: bwa (alignment via Burrows-Wheeler transformation)\n    ## Version: 0.7.17-r1188\n    ## Contact: Heng Li \u003clh3@sanger.ac.uk\u003e\n    ## \n    ## Usage:   bwa \u003ccommand\u003e [options]\n    ## \n    ## Command: index         index sequences in the FASTA format\n    ##          mem           BWA-MEM algorithm\n    ##          fastmap       identify super-maximal exact matches\n    ##          pemerge       merge overlapping paired ends (EXPERIMENTAL)\n    ##          aln           gapped/ungapped alignment\n    ##          samse         generate alignment (single ended)\n    ##          sampe         generate alignment (paired ended)\n    ##          bwasw         BWA-SW for long queries\n    ## \n    ##          shm           manage indices in shared memory\n    ##          fa2pac        convert FASTA to PAC format\n    ##          pac2bwt       generate BWT from PAC\n    ##          pac2bwtgen    alternative algorithm for generating BWT\n    ##          bwtupdate     update .bwt to the new format\n    ##          bwt2sa        generate SA from BWT and Occ\n    ## \n    ## Note: To use BWA, you need to first index the genome with `bwa index'.\n    ##       There are three alignment algorithms in BWA: `mem', `bwasw', and\n    ##       `aln/samse/sampe'. If you are not sure which to use, try `bwa mem'\n    ##       first. Please `man ./bwa.1' for the manual.\n\n## Setting environment variables\n\nCreate a new environment variable (ENV) using `--env`.\n\n``` bash\ndocker run --rm --env YEAR=1984 busybox env\n```\n\n    ## Unable to find image 'busybox:latest' locally\n    ## latest: Pulling from library/busybox\n    ## 80bfbb8a41a2: Pulling fs layer\n    ## 80bfbb8a41a2: Download complete\n    ## 80bfbb8a41a2: Pull complete\n    ## Digest: sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e\n    ## Status: Downloaded newer image for busybox:latest\n    ## PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n    ## HOSTNAME=b103f016ad65\n    ## YEAR=1984\n    ## HOME=/root\n\nTwo ENVs.\n\n``` bash\ndocker run --rm --env YEAR=1984 --env SEED=2049 busybox env\n```\n\n    ## PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n    ## HOSTNAME=b86b07e2422d\n    ## YEAR=1984\n    ## SEED=2049\n    ## HOME=/root\n\nOr `-e` for less typing.\n\n``` bash\ndocker run --rm -e YEAR=1984 -e SEED=2049 busybox env\n```\n\n    ## PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n    ## HOSTNAME=5aa9f04852ef\n    ## YEAR=1984\n    ## SEED=2049\n    ## HOME=/root\n\n## Resource usage\n\nTo\n[restrict](https://docs.docker.com/config/containers/resource_constraints/)\nCPU usage use `--cpus=n` and use `--memory=` to restrict the maximum\namount of memory the container can use.\n\nWe can confirm the limited CPU usage by running an endless while loop\nand using `docker stats` to confirm the CPU usage. *Remember to use\n`docker stop` to stop the container after confirming the usage!*\n\nRestrict to 1 CPU.\n\n``` console\n# run in detached mode\ndocker run --rm -d --cpus=1 davetang/bwa:0.7.17 perl -le 'while(1){ }'\n\n# check stats and use control+c to exit\ndocker stats\nCONTAINER ID   NAME             CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O   PIDS\n8cc20bcfa4f4   vigorous_khorana   100.59%   572KiB / 1.941GiB   0.03%     736B / 0B   0B / 0B     1\n\ndocker stop 8cc20bcfa4f4\n```\n\nRestrict to 1/2 CPU.\n\n``` console\n# run in detached mode\ndocker run --rm -d --cpus=0.5 davetang/bwa:0.7.17 perl -le 'while(1){ }'\n\n# check stats and use control+c to exit\ndocker stats\n\nCONTAINER ID   NAME             CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O   PIDS\naf6e812a94da   unruffled_liskov   50.49%    584KiB / 1.941GiB   0.03%     736B / 0B   0B / 0B     1\n\ndocker stop af6e812a94da\n```\n\n## Copying files between host and container\n\nUse `docker cp` but I recommend mounting a volume to a Docker container\n(see next section).\n\n``` console\ndocker cp --help\n\nUsage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-\n        docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH\n\nCopy files/folders between a container and the local filesystem\n\nOptions:\n  -L, --follow-link   Always follow symbol link in SRC_PATH\n      --help          Print usage\n\n# find container name\ndocker ps -a\n\n# create file to transfer\necho hi \u003e hi.txt\n\ndocker cp hi.txt fee424ef6bf0:/root/\n\n# start container\ndocker start -ai fee424ef6bf0\n\n# inside container\ncat /root/hi.txt \nhi\n\n# create file inside container\necho bye \u003e /root/bye.txt\nexit\n\n# transfer file from container to host\ndocker cp fee424ef6bf0:/root/bye.txt .\n\ncat bye.txt \nbye\n```\n\n## Sharing between host and container\n\nUse the `-v` flag to mount directories to a container so that you can\nshare files between the host and container.\n\nIn the example below, I am mounting `data` from the current directory\n(using the Unix command `pwd`) to `/work` in the container. I am working\nfrom the root directory of this GitHub repository, which contains the\n`data` directory.\n\n``` bash\nls data\n```\n\n    ## README.md\n    ## chrI.fa.gz\n\nAny output written to `/work` inside the container, will be accessible\ninside `data` on the host. The command below will create BWA index files\nfor `data/chrI.fa.gz`.\n\n``` bash\ndocker run --rm -v $(pwd)/data:/work davetang/bwa:0.7.17 bwa index chrI.fa.gz\n```\n\n    ## [bwa_index] Pack FASTA... 0.14 sec\n    ## [bwa_index] Construct BWT for the packed sequence...\n    ## [bwa_index] 3.25 seconds elapse.\n    ## [bwa_index] Update BWT... 0.06 sec\n    ## [bwa_index] Pack forward-only FASTA... 0.11 sec\n    ## [bwa_index] Construct SA from BWT and Occ... 0.95 sec\n    ## [main] Version: 0.7.17-r1188\n    ## [main] CMD: bwa index chrI.fa.gz\n    ## [main] Real time: 4.530 sec; CPU: 4.538 sec\n\nWe can see the newly created index files.\n\n``` bash\nls -lrt data\n```\n\n    ## total 30436\n    ## -rw-r--r-- 1 runner runner      194 Sep 20 02:51 README.md\n    ## -rw-r--r-- 1 runner runner  4772981 Sep 20 02:51 chrI.fa.gz\n    ## -rw-r--r-- 1 root   root   15072516 Sep 20 02:57 chrI.fa.gz.bwt\n    ## -rw-r--r-- 1 root   root    3768110 Sep 20 02:57 chrI.fa.gz.pac\n    ## -rw-r--r-- 1 root   root         41 Sep 20 02:57 chrI.fa.gz.ann\n    ## -rw-r--r-- 1 root   root         13 Sep 20 02:57 chrI.fa.gz.amb\n    ## -rw-r--r-- 1 root   root    7536272 Sep 20 02:57 chrI.fa.gz.sa\n\nHowever note that the generated files are owned by `root`, which is\nslightly annoying because unless we have root access, we need to start a\nDocker container with the volume re-mounted to alter/delete the files.\n\n### File permissions\n\nAs seen above, files generated inside the container on a mounted volume\nare owned by `root`. This is because the default user inside a Docker\ncontainer is `root`. In Linux, there is typically a `root` user with the\nUID and GID of 0; this user exists in the host Linux environment (where\nthe Docker engine is running) as well as inside the Docker container.\n\nIn the example below, the mounted volume is owned by UID 1211 and GID\n1211 (in the host environment). This UID and GID does not exist in the\nDocker container, thus the UID and GID are shown instead of a name like\n`root`. This is important to understand because to circumvent this file\npermission issue, we need to create a user that matches the UID and GID\nin the host environment.\n\n``` console\nls -lrt\n# total 2816\n# -rw-r--r-- 1 1211 1211 1000015 Apr 27 02:00 ref.fa\n# -rw-r--r-- 1 1211 1211   21478 Apr 27 02:00 l100_n100_d400_31_2.fq\n# -rw-r--r-- 1 1211 1211   21478 Apr 27 02:00 l100_n100_d400_31_1.fq\n# -rw-r--r-- 1 1211 1211     119 Apr 27 02:01 run.sh\n# -rw-r--r-- 1 root root 1000072 Apr 27 02:03 ref.fa.bwt\n# -rw-r--r-- 1 root root  250002 Apr 27 02:03 ref.fa.pac\n# -rw-r--r-- 1 root root      40 Apr 27 02:03 ref.fa.ann\n# -rw-r--r-- 1 root root      12 Apr 27 02:03 ref.fa.amb\n# -rw-r--r-- 1 root root  500056 Apr 27 02:03 ref.fa.sa\n# -rw-r--r-- 1 root root   56824 Apr 27 02:04 aln.sam\n```\n\nAs mentioned already, having `root` ownership is problematic because\nwhen we are back in the host environment, we can’t modify these files.\nTo circumvent this, we can create a user that matches the host user by\npassing three environmental variables from the host to the container.\n\n``` console\ndocker run -it \\\n  -v ~/my_data:/data \\\n  -e MYUID=$(id -u) \\\n  -e MYGID=$(id -g) \\\n  -e ME=$(whoami) \\\n  bwa /bin/bash\n```\n\nWe use the environment variables and the following steps to create an\nidentical user inside the container.\n\n``` console\nadduser --quiet --home /home/san/$ME --no-create-home --gecos \"\" --shell /bin/bash --disabled-password $ME\n\n# optional: give yourself admin privileges\necho \"%$ME ALL=(ALL) NOPASSWD:ALL\" \u003e\u003e /etc/sudoers\n\n# update the IDs to those passed into Docker via environment variable\nsed -i -e \"s/1000:1000/$MYUID:$MYGID/g\" /etc/passwd\nsed -i -e \"s/$ME:x:1000/$ME:x:$MYGID/\" /etc/group\n\n# su - as the user\nexec su - $ME\n\n# run BWA again, after you have deleted the old files as root\nbwa index ref.fa\nbwa mem ref.fa l100_n100_d400_31_1.fq l100_n100_d400_31_2.fq \u003e aln.sam\n\n# check output\nls -lrt\n# total 2816\n# -rw-r--r-- 1 dtang dtang 1000015 Apr 27 02:00 ref.fa\n# -rw-r--r-- 1 dtang dtang   21478 Apr 27 02:00 l100_n100_d400_31_2.fq\n# -rw-r--r-- 1 dtang dtang   21478 Apr 27 02:00 l100_n100_d400_31_1.fq\n# -rw-r--r-- 1 dtang dtang     119 Apr 27 02:01 run.sh\n# -rw-rw-r-- 1 dtang dtang 1000072 Apr 27 02:12 ref.fa.bwt\n# -rw-rw-r-- 1 dtang dtang  250002 Apr 27 02:12 ref.fa.pac\n# -rw-rw-r-- 1 dtang dtang      40 Apr 27 02:12 ref.fa.ann\n# -rw-rw-r-- 1 dtang dtang      12 Apr 27 02:12 ref.fa.amb\n# -rw-rw-r-- 1 dtang dtang  500056 Apr 27 02:12 ref.fa.sa\n# -rw-rw-r-- 1 dtang dtang   56824 Apr 27 02:12 aln.sam\n\n# exit container\nexit\n```\n\nThis time when you check the file permissions in the host environment,\nthey should match your username.\n\n``` console\nls -lrt ~/my_data\n# total 2816\n# -rw-r--r-- 1 dtang dtang 1000015 Apr 27 10:00 ref.fa\n# -rw-r--r-- 1 dtang dtang   21478 Apr 27 10:00 l100_n100_d400_31_2.fq\n# -rw-r--r-- 1 dtang dtang   21478 Apr 27 10:00 l100_n100_d400_31_1.fq\n# -rw-r--r-- 1 dtang dtang     119 Apr 27 10:01 run.sh\n# -rw-rw-r-- 1 dtang dtang 1000072 Apr 27 10:12 ref.fa.bwt\n# -rw-rw-r-- 1 dtang dtang  250002 Apr 27 10:12 ref.fa.pac\n# -rw-rw-r-- 1 dtang dtang      40 Apr 27 10:12 ref.fa.ann\n# -rw-rw-r-- 1 dtang dtang      12 Apr 27 10:12 ref.fa.amb\n# -rw-rw-r-- 1 dtang dtang  500056 Apr 27 10:12 ref.fa.sa\n# -rw-rw-r-- 1 dtang dtang   56824 Apr 27 10:12 aln.sam\n```\n\n### File Permissions 2\n\nThere is a `-u` or `--user` parameter that can be used with `docker run`\nto run a container using a specific user. This is easier than creating a\nnew user.\n\nIn this example we run the `touch` command as `root`.\n\n``` bash\ndocker run -v $(pwd):/$(pwd) ubuntu:22.10 touch $(pwd)/test_root.txt\nls -lrt $(pwd)/test_root.txt\n```\n\n    ## Unable to find image 'ubuntu:22.10' locally\n    ## 22.10: Pulling from library/ubuntu\n    ## 3ad6ea492c35: Pulling fs layer\n    ## 3ad6ea492c35: Verifying Checksum\n    ## 3ad6ea492c35: Download complete\n    ## 3ad6ea492c35: Pull complete\n    ## Digest: sha256:e322f4808315c387868a9135beeb11435b5b83130a8599fd7d0014452c34f489\n    ## Status: Downloaded newer image for ubuntu:22.10\n    ## -rw-r--r-- 1 root root 0 Sep 20 02:57 /home/runner/work/learning_docker/learning_docker/test_root.txt\n\nIn this example, we run the command as a user with the same UID and GID;\nthe `stat` command is used to get the UID and GID.\n\n``` bash\ndocker run -v $(pwd):/$(pwd) -u $(stat -c \"%u:%g\" $HOME) ubuntu:22.10 touch $(pwd)/test_mine.txt\nls -lrt $(pwd)/test_mine.txt\n```\n\n    ## -rw-r--r-- 1 runner runner 0 Sep 20 02:57 /home/runner/work/learning_docker/learning_docker/test_mine.txt\n\nOne issue with this method is that you may encounter the following\nwarning (if running interactively):\n\n    groups: cannot find name for group ID 1000\n    I have no name!@ed9e8b6b7622:/$\n\nThis is because the user in your host environment does not exist in the\ncontainer environment. As far as I am aware, this is not a problem; we\njust want to create files/directories with matching user and group IDs.\n\n### Read only\n\nTo mount a volume but with read-only permissions, append `:ro` at the\nend.\n\n``` bash\ndocker run --rm -v $(pwd):/work:ro davetang/bwa:0.7.17 touch test.txt\n```\n\n    ## touch: cannot touch 'test.txt': Read-only file system\n\n## Removing the image\n\nUse `docker rmi` to remove an image. You will need to remove any stopped\ncontainers first before you can remove an image. Use `docker ps -a` to\nfind stopped containers and `docker rm` to remove these containers.\n\nLet’s pull the `busybox` image.\n\n``` bash\ndocker pull busybox\n```\n\n    ## Using default tag: latest\n    ## latest: Pulling from library/busybox\n    ## Digest: sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e\n    ## Status: Image is up to date for busybox:latest\n    ## docker.io/library/busybox:latest\n\nCheck out `busybox`.\n\n``` bash\ndocker images busybox\n```\n\n    ## REPOSITORY   TAG       IMAGE ID       CREATED         SIZE\n    ## busybox      latest    0ed463b26dae   11 months ago   4.43MB\n\nRemove `busybox`.\n\n``` bash\ndocker rmi busybox\n```\n\n    ## Untagged: busybox:latest\n    ## Untagged: busybox@sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e\n    ## Deleted: sha256:0ed463b26daee791b094dc3fff25edb3e79f153d37d274e5c2936923c38dac2b\n    ## Deleted: sha256:80e840de630d08a6a1e0ee30e7c8378cf1ed6a424315d7e437f54780aee6bf5a\n\n## Committing changes\n\nGenerally, it is better to use a Dockerfile to manage your images in a\ndocumented and maintainable way but if you still want to [commit\nchanges](https://docs.docker.com/engine/reference/commandline/commit/)\nto your container (like you would for Git), read on.\n\nWhen you log out of a container, the changes made are still stored; type\n`docker ps -a` to see all containers and the latest changes. Use\n`docker commit` to commit your changes.\n\n``` console\ndocker ps -a\n\n# git style commit\n# -a, --author=       Author (e.g., \"John Hannibal Smith \u003channibal@a-team.com\u003e\")\n# -m, --message=      Commit message\ndocker commit -m 'Made change to blah' -a 'Dave Tang' \u003cCONTAINER ID\u003e \u003cimage\u003e\n\n# use docker history \u003cimage\u003e to check history\ndocker history \u003cimage\u003e\n```\n\n## Access running container\n\nTo access a container that is already running, perhaps in the background\n(using detached mode: `docker run` with `-d`) use `docker ps` to find\nthe name of the container and then use `docker exec`.\n\nIn the example below, my container name is `rstudio_dtang`.\n\n``` console\ndocker exec -it rstudio_dtang /bin/bash\n```\n\n## Cleaning up exited containers\n\nI typically use the `--rm` flag with `docker run` so that containers are\nautomatically removed after I exit them. However, if you don’t use\n`--rm`, by default a container’s file system persists even after the\ncontainer exits. For example:\n\n``` bash\ndocker run hello-world\n```\n\n    ## \n    ## Hello from Docker!\n    ## This message shows that your installation appears to be working correctly.\n    ## \n    ## To generate this message, Docker took the following steps:\n    ##  1. The Docker client contacted the Docker daemon.\n    ##  2. The Docker daemon pulled the \"hello-world\" image from the Docker Hub.\n    ##     (amd64)\n    ##  3. The Docker daemon created a new container from that image which runs the\n    ##     executable that produces the output you are currently reading.\n    ##  4. The Docker daemon streamed that output to the Docker client, which sent it\n    ##     to your terminal.\n    ## \n    ## To try something more ambitious, you can run an Ubuntu container with:\n    ##  $ docker run -it ubuntu bash\n    ## \n    ## Share images, automate workflows, and more with a free Docker ID:\n    ##  https://hub.docker.com/\n    ## \n    ## For more examples and ideas, visit:\n    ##  https://docs.docker.com/get-started/\n\nShow all containers.\n\n``` bash\ndocker ps -a\n```\n\n    ## CONTAINER ID   IMAGE          COMMAND                  CREATED                  STATUS                              PORTS     NAMES\n    ## ad67e22d1167   hello-world    \"/hello\"                 Less than a second ago   Exited (0) Less than a second ago             vigilant_panini\n    ## 65f0704bff8e   ubuntu:22.10   \"touch /home/runner/…\"   2 seconds ago            Exited (0) 1 second ago                       naughty_bhaskara\n    ## 25d371e800b0   ubuntu:22.10   \"touch /home/runner/…\"   2 seconds ago            Exited (0) 1 second ago                       gracious_boyd\n\nWe can use a sub-shell to get all (`-a`) container IDs (`-q`) that have\nexited (`-f status=exited`) and then remove them (`docker rm -v`).\n\n``` bash\ndocker rm -v $(docker ps -a -q -f status=exited)\n```\n\n    ## ad67e22d1167\n    ## 65f0704bff8e\n    ## 25d371e800b0\n\nCheck to see if the container still exists.\n\n``` bash\ndocker ps -a\n```\n\n    ## CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n\nWe can set this up as a Bash script so that we can easily remove exited\ncontainers. In the Bash script `-z` returns true if `$exited` is empty,\ni.e. no exited containers, so we will only run the command when\n`$exited` is not true.\n\n``` bash\ncat clean_up_docker.sh\n```\n\n    ## #!/usr/bin/env bash\n    ## \n    ## set -euo pipefail\n    ## \n    ## exited=`docker ps -a -q -f status=exited`\n    ## \n    ## if [[ ! -z ${exited} ]]; then\n    ##    docker rm -v $(docker ps -a -q -f status=exited)\n    ## fi\n    ## \n    ## exit 0\n\nAs I have mentioned, you can use the\n[–rm](https://docs.docker.com/engine/reference/run/#clean-up---rm)\nparameter to automatically clean up the container and remove the file\nsystem when the container exits.\n\n``` bash\ndocker run --rm hello-world\n```\n\n    ## \n    ## Hello from Docker!\n    ## This message shows that your installation appears to be working correctly.\n    ## \n    ## To generate this message, Docker took the following steps:\n    ##  1. The Docker client contacted the Docker daemon.\n    ##  2. The Docker daemon pulled the \"hello-world\" image from the Docker Hub.\n    ##     (amd64)\n    ##  3. The Docker daemon created a new container from that image which runs the\n    ##     executable that produces the output you are currently reading.\n    ##  4. The Docker daemon streamed that output to the Docker client, which sent it\n    ##     to your terminal.\n    ## \n    ## To try something more ambitious, you can run an Ubuntu container with:\n    ##  $ docker run -it ubuntu bash\n    ## \n    ## Share images, automate workflows, and more with a free Docker ID:\n    ##  https://hub.docker.com/\n    ## \n    ## For more examples and ideas, visit:\n    ##  https://docs.docker.com/get-started/\n\nNo containers.\n\n``` bash\ndocker ps -a\n```\n\n    ## CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n\n## Installing Perl modules\n\nUse `cpanminus`.\n\n``` console\napt-get install -y cpanminus\n\n# install some Perl modules\ncpanm Archive::Extract Archive::Zip DBD::mysql\n```\n\n## Creating a data container\n\nThis [guide on working with Docker data\nvolumes](https://www.digitalocean.com/community/tutorials/how-to-work-with-docker-data-volumes-on-ubuntu-14-04)\nprovides a really nice introduction. Use `docker create` to create a\ndata container; the `-v` indicates the directory for the data container;\nthe `--name data_container` indicates the name of the data container;\nand `ubuntu` is the image to be used for the container.\n\n``` console\ndocker create -v /tmp --name data_container ubuntu\n```\n\nIf we run a new Ubuntu container with the `--volumes-from` flag, output\nwritten to the `/tmp` directory will be saved to the `/tmp` directory of\nthe `data_container` container.\n\n``` console\ndocker run -it --volumes-from data_container ubuntu /bin/bash\n```\n\n## R\n\nUse images from [The Rocker Project](https://www.rocker-project.org/),\nfor example `rocker/r-ver:4.3.0`.\n\n``` bash\ndocker run --rm rocker/r-ver:4.3.0\n```\n\n    ## Unable to find image 'rocker/r-ver:4.3.0' locally\n    ## 4.3.0: Pulling from rocker/r-ver\n    ## 3c645031de29: Pulling fs layer\n    ## eb5ba85ece65: Pulling fs layer\n    ## 336082e130a7: Pulling fs layer\n    ## d6f516f66899: Pulling fs layer\n    ## e7191ae70de7: Pulling fs layer\n    ## d6f516f66899: Waiting\n    ## e7191ae70de7: Waiting\n    ## eb5ba85ece65: Download complete\n    ## d6f516f66899: Verifying Checksum\n    ## d6f516f66899: Download complete\n    ## 3c645031de29: Verifying Checksum\n    ## 3c645031de29: Download complete\n    ## 3c645031de29: Pull complete\n    ## eb5ba85ece65: Pull complete\n    ## e7191ae70de7: Download complete\n    ## 336082e130a7: Verifying Checksum\n    ## 336082e130a7: Download complete\n    ## 336082e130a7: Pull complete\n    ## d6f516f66899: Pull complete\n    ## e7191ae70de7: Pull complete\n    ## Digest: sha256:48fb09f63e1cbcc1b0ce3974a8f206bff0804b6921bb36dfa08eafa264dad542\n    ## Status: Downloaded newer image for rocker/r-ver:4.3.0\n    ## \n    ## R version 4.3.0 (2023-04-21) -- \"Already Tomorrow\"\n    ## Copyright (C) 2023 The R Foundation for Statistical Computing\n    ## Platform: x86_64-pc-linux-gnu (64-bit)\n    ## \n    ## R is free software and comes with ABSOLUTELY NO WARRANTY.\n    ## You are welcome to redistribute it under certain conditions.\n    ## Type 'license()' or 'licence()' for distribution details.\n    ## \n    ##   Natural language support but running in an English locale\n    ## \n    ## R is a collaborative project with many contributors.\n    ## Type 'contributors()' for more information and\n    ## 'citation()' on how to cite R or R packages in publications.\n    ## \n    ## Type 'demo()' for some demos, 'help()' for on-line help, or\n    ## 'help.start()' for an HTML browser interface to help.\n    ## Type 'q()' to quit R.\n    ## \n    ## \u003e\n\n## Saving and transferring a Docker image\n\nYou should just share the Dockerfile used to create your image but if\nyou need another way to save and share an image, see [this\npost](http://stackoverflow.com/questions/23935141/how-to-copy-docker-images-from-one-host-to-another-without-via-repository)\non Stack Overflow.\n\n``` console\ndocker save -o \u003csave image to path\u003e \u003cimage name\u003e\ndocker load -i \u003cpath to image tar file\u003e\n```\n\nHere’s an example.\n\n``` console\n# save on Unix server\ndocker save -o davebox.tar davebox\n\n# copy file to MacBook Pro\nscp davetang@192.168.0.31:/home/davetang/davebox.tar .\n\ndocker load -i davebox.tar \n93c22f563196: Loading layer [==================================================\u003e] 134.6 MB/134.6 MB\n...\n\ndocker images\nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\ndavebox             latest              d38f27446445        10 days ago         3.46 GB\n\ndocker run davebox samtools\n\nProgram: samtools (Tools for alignments in the SAM format)\nVersion: 1.3 (using htslib 1.3)\n\nUsage:   samtools \u003ccommand\u003e [options]\n...\n```\n\n## Sharing your image\n\n### Docker Hub\n\nCreate an account on [Docker Hub](https://hub.docker.com/); my account\nis `davetang`. Use `docker login` to login and use `docker push` to push\nto Docker Hub (run `docker tag` first if you didn’t name your image in\nthe format of `yourhubusername/newrepo`).\n\n``` console\ndocker login\n\n# create repo on Docker Hub then tag your image\ndocker tag bb38976d03cf yourhubusername/newrepo\n\n# push\ndocker push yourhubusername/newrepo\n```\n\n### Quay.io\n\nCreate an account on [Quay.io](https://quay.io/); you can use Quay.io\nfor free as stated in their [plans](https://quay.io/plans/):\n\n\u003e Can I use Quay for free? Yes! We offer unlimited storage and serving\n\u003e of public repositories. We strongly believe in the open source\n\u003e community and will do what we can to help!\n\nUse `docker login` to [login](https://docs.quay.io/guides/login.html)\nand use the credentials you set up when you created an account on\nQuay.io.\n\n``` console\ndocker login quay.io\n```\n\nQuay.io images are prefixed with `quay.io`, so I used `docker image tag`\nto create a new tag of my RStudio Server image. (Unfortunately, the\nusername `davetang` was taken on RedHat \\[possibly by me a long time\nago\\], so I have to use `davetang31` on Quay.io.)\n\n``` console\ndocker image tag davetang/rstudio:4.2.2 quay.io/davetang31/rstudio:4.2.2\n```\n\nPush to Quay.io.\n\n``` console\ndocker push quay.io/davetang31/rstudio:4.2.2\n```\n\n### GitHub Actions\n\n[login-action](https://github.com/docker/login-action) is used to\nautomatically login to [Docker\nHub](https://github.com/docker/login-action#docker-hub) when using\nGitHub Actions. This allows images to be automatically built and pushed\nto Docker Hub. There is also support for\n[Quay.io](https://github.com/docker/login-action#quayio).\n\n## Tips\n\nTip from\n\u003chttps://support.pawsey.org.au/documentation/display/US/Containers\u003e:\neach RUN, COPY, and ADD command in a Dockerfile generates another layer\nin the container thus increasing its size; use multi-line commands and\nclean up package manager caches to minimise image size:\n\n``` console\nRUN apt-get update \\\n      \u0026\u0026 apt-get install -y \\\n         autoconf \\\n         automake \\\n         gcc \\\n         g++ \\\n         python \\\n         python-dev \\\n      \u0026\u0026 apt-get clean all \\\n      \u0026\u0026 rm -rf /var/lib/apt/lists/*\n```\n\nI have found it handy to mount my current directory to the same path\ninside a Docker container and to [set it as the working\ndirectory](https://docs.docker.com/engine/reference/commandline/run/#set-working-directory--w);\nthe directory will be automatically created inside the container if it\ndoes not already exist. When the container starts up, I will\nconveniently be in my current directory. In the command below I have\nalso added the `-u` option, which sets the user to\n`\u003cname|uid\u003e[:\u003cgroup|gid\u003e]`.\n\n``` console\ndocker run --rm -it -u $(stat -c \"%u:%g\" ${HOME}) -v $(pwd):$(pwd) -w $(pwd) davetang/build:1.1 /bin/bash\n```\n\nIf you do not want to preface `docker` with `sudo`, create a Unix group\ncalled `docker` and add users to it. On some Linux distributions, the\nsystem automatically creates this group when installing Docker Engine\nusing a package manager. In that case, there is no need for you to\nmanually create the group. Check `/etc/group` to see if the `docker`\ngroup exists.\n\n``` console\ncat /etc/group | grep docker\n```\n\nIf the `docker` group does not exist, create the group:\n\n``` console\nsudo groupadd docker\n```\n\nAdd users to the group.\n\n``` console\nsudo usermod -aG docker $USER\n```\n\nThe user will need to log out and log back in, before the changes take\neffect.\n\nOn Linux, Docker is installed in `/var/lib/docker`.\n\n``` console\ndocker info -f '{{ .DockerRootDir }}'\n# /var/lib/docker\n```\n\nThis may not be ideal depending on your partitioning. To change the\ndefault root directory update the daemon configuration file; the default\nlocation on Linux is `/etc/docker/daemon.json`. This file may not exist,\nso you need to create it.\n\nThe example below makes `/home/docker` the Docker root directory; you\ncan use any directory you want but just make sure it exists.\n\n``` console\ncat /etc/docker/daemon.json\n```\n\n    {\n       \"data-root\": \"/home/docker\"\n    }\n\nRestart the Docker server (this will take a little time, since all the\nfiles will be copied to the new location) and then check the Docker root\ndirectory.\n\n``` console\nsudo systemctl restart docker\ndocker info -f '{{ .DockerRootDir}}'\n```\n\n    /home/docker\n\nCheck out the new home!\n\n``` console\nsudo ls -1 /home/docker\n```\n\n    buildkit\n    containers\n    engine-id\n    image\n    network\n    overlay2\n    plugins\n    runtimes\n    swarm\n    tmp\n    volumes\n\nUse `--progress=plain` to show container output, which is useful for\ndebugging!\n\n``` console\ndocker build --progress=plain -t davetang/scanpy:3.11 .\n```\n\nFor Apple laptops using the the M\\[123\\] chips, use\n`--platform linux/amd64` if that’s the architecture of the image.\n\n    docker run --rm --platform linux/amd64 -p 8787:8787 rocker/verse:4.4.1/\n\n## Useful links\n\n- [Post installation\n  steps](https://docs.docker.com/engine/install/linux-postinstall/)\n- [A quick introduction to\n  Docker](http://blog.scottlowe.org/2014/03/11/a-quick-introduction-to-docker/)\n- [The BioDocker project](https://github.com/BioDocker/biodocker); check\n  out their [Wiki](https://github.com/BioDocker/biodocker/wiki), which\n  has a lot of useful information\n- [The impact of Docker containers on the performance of genomic\n  pipelines](http://www.ncbi.nlm.nih.gov/pubmed/26421241)\n- [Learn enough Docker to be\n  useful](https://towardsdatascience.com/learn-enough-docker-to-be-useful-b0b44222eef5)\n- [10 things to avoid in Docker\n  containers](http://developers.redhat.com/blog/2016/02/24/10-things-to-avoid-in-docker-containers/)\n- The [Play with Docker\n  classroom](https://training.play-with-docker.com/) brings you labs and\n  tutorials that help you get hands-on experience using Docker\n- [Shifter](https://github.com/NERSC/shifter) enables container images\n  for HPC\n- \u003chttp://biocworkshops2019.bioconductor.org.s3-website-us-east-1.amazonaws.com/page/BioconductorOnContainers__Bioconductor_Containers_Workshop/\u003e\n- Run the Docker daemon as a non-root user ([Rootless\n  mode](https://docs.docker.com/engine/security/rootless/))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavetang%2Flearning_docker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavetang%2Flearning_docker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavetang%2Flearning_docker/lists"}