From 7af66e7bbb4e81e03bbfdef3f6c12b32efd36db2 Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Wed, 26 Sep 2018 15:59:41 -0700 Subject: [PATCH 1/6] renaming a few functions --- entrypoint.sh | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 22a77b5..9767204 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -197,32 +197,32 @@ stop() { ### runtime environment detection ###################################################################################### -get_reqd_nfs_version() { +get_requested_nfs_version() { echo "${!ENV_VAR_NFS_VERSION:-$DEFAULT_NFS_VERSION}" } -get_reqd_nfsd_threads() { +get_requested_count_nfsd_threads() { echo "${!ENV_VAR_NFS_SERVER_THREAD_COUNT:-$DEFAULT_NFS_SERVER_THREAD_COUNT}" } -get_reqd_mountd_port() { +get_requested_port_mountd() { echo "${!ENV_VAR_NFS_PORT_MOUNTD:-$DEFAULT_NFS_PORT_MOUNTD}" } -get_reqd_nfsd_port() { +get_requested_port_nfsd() { echo "${!ENV_VAR_NFS_PORT:-$DEFAULT_NFS_PORT}" } -get_reqd_statd_in_port() { +get_requested_port_statd_in() { echo "${!ENV_VAR_NFS_PORT_STATD_IN:-$DEFAULT_NFS_PORT_STATD_IN}" } -get_reqd_statd_out_port() { +get_requested_port_statd_out() { echo "${!ENV_VAR_NFS_PORT_STATD_OUT:-$DEFAULT_NFS_PORT_STATD_OUT}" } @@ -276,17 +276,19 @@ assert_port() { assert_nfs_version() { - get_reqd_nfs_version | grep -Eq '^(3|4|4\.1|4\.2)$' + local -r version="$(get_requested_nfs_version)" + + echo "$version" | grep -Eq '^(3|4|4\.1|4\.2)$' on_failure bail "please set $ENV_VAR_NFS_VERSION to one of: 4.2, 4.1, 4, 3" - if [[ -z "$(is_nfs3_enabled)" && "$(get_reqd_nfs_version)" == '3' ]]; then + if [[ -z "$(is_nfs3_enabled)" && "$version" = '3' ]]; then bail 'you cannot simultaneously enable and disable NFS version 3' fi } assert_nfsd_threads() { - local -r reqd_thread_count=$(get_reqd_nfsd_threads) + local -r reqd_thread_count=$(get_requested_count_nfsd_threads) if [[ "$reqd_thread_count" -lt 1 ]]; then bail "please set $ENV_VAR_NFS_SERVER_THREAD_COUNT to a positive integer" @@ -433,14 +435,14 @@ boot_helper_mount() { boot_helper_get_version_flags() { - local -r reqd_version="$(get_reqd_nfs_version)" + local -r reqd_version="$(get_requested_nfs_version)" local flags=('--nfs-version' "$reqd_version" '--no-nfs-version' 2) if [[ -z "$(is_nfs3_enabled)" ]]; then flags+=('--no-nfs-version' 3) fi - if [[ "$reqd_version" == '3' ]]; then + if [[ "$reqd_version" = '3' ]]; then flags+=('--no-nfs-version' 4) fi @@ -470,7 +472,7 @@ boot_main_mountd() { local version_flags read -r -a version_flags <<< "$(boot_helper_get_version_flags)" - local -r port=$(get_reqd_mountd_port) + local -r port=$(get_requested_port_mountd) local -r args=('--debug' 'all' '--port' "$port" "${version_flags[@]}") # yes, rpc.mountd is required even for NFS v4: https://forums.gentoo.org/viewtopic-p-7724856.html#7724856 @@ -491,7 +493,7 @@ boot_main_rpcbind() { boot_main_idmapd() { - if [[ "$(get_reqd_nfs_version)" != '3' && -f "$PATH_FILE_ETC_IDMAPD_CONF" ]]; then + if [[ "$(get_requested_nfs_version)" != '3' && -f "$PATH_FILE_ETC_IDMAPD_CONF" ]]; then log 'starting idmapd' $PATH_BIN_IDMAPD -v -S on_failure stop 'idmapd failed' @@ -504,8 +506,8 @@ boot_main_statd() { return fi - local -r port_in=$(get_reqd_statd_in_port) - local -r port_out=$(get_reqd_statd_out_port) + local -r port_in=$(get_requested_port_statd_in) + local -r port_out=$(get_requested_port_statd_out) local -r args=('--no-notify' '--port' "$port_in" '--outgoing-port' "$port_out") log "starting statd on port $port_in (outgoing connections from port $port_out)" @@ -517,8 +519,8 @@ boot_main_nfsd() { local version_flags read -r -a version_flags <<< "$(boot_helper_get_version_flags)" - local -r threads=$(get_reqd_nfsd_threads) - local -r port=$(get_reqd_nfsd_port) + local -r threads=$(get_requested_count_nfsd_threads) + local -r port=$(get_requested_port_nfsd) local -r args=('--debug' 8 '--port' "$port" "${version_flags[@]}" "$threads") log "starting rpc.nfsd on port $port with $threads server thread(s)" @@ -548,7 +550,7 @@ boot_main_svcgssd() { summarize_nfs_versions() { - local -r reqd_version="$(get_reqd_nfs_version)" + local -r reqd_version="$(get_requested_nfs_version)" local versions='' case "$reqd_version" in @@ -592,7 +594,9 @@ summarize_exports() { summarize_ports() { - local -r port_nfsd="$(get_reqd_nfsd_port)" + local -r port_nfsd="$(get_requested_port_nfsd)" + local -r port_mountd="$(get_requested_port_mountd)" + local -r port_statd_in="$(get_requested_port_statd_in)" if [[ -z "$(is_nfs3_enabled)" ]]; then log "list of container ports that should be exposed: $port_nfsd (TCP)" @@ -600,8 +604,8 @@ summarize_ports() { log 'list of container ports that should be exposed:' log ' 111 (TCP and UDP)' log " $port_nfsd (TCP and UDP)" - log " $(get_reqd_statd_in_port) (TCP and UDP)" - log " $(get_reqd_mountd_port) (TCP and UDP)" + log " $port_statd_in (TCP and UDP)" + log " $port_mountd (TCP and UDP)" fi } From f283d488aadcff42110ad8ad0971aebb2a0b7a0b Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Thu, 27 Sep 2018 12:08:27 -0700 Subject: [PATCH 2/6] code cleanup and ditch redundant shutdown steps --- entrypoint.sh | 70 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 9767204..5308a60 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -82,8 +82,7 @@ log_error() { log_header() { - echo "\ - + echo " ================================================================== $(echo "$1" | awk '{print toupper($0)}') ==================================================================" @@ -169,7 +168,7 @@ stop_nfsd() { stop_exportfs() { log 'un-exporting filesystem(s)' - $PATH_BIN_EXPORTFS -ua + $PATH_BIN_EXPORTFS -uav on_failure warn 'unable to un-export filesystem(s)' } @@ -177,10 +176,20 @@ stop() { log_header 'terminating ...' - kill_process_if_running "$PATH_BIN_RPC_SVCGSSD" + if is_kerberos_enabled; then + kill_process_if_running "$PATH_BIN_RPC_SVCGSSD" + fi + stop_nfsd - kill_process_if_running "$PATH_BIN_IDMAPD" - kill_process_if_running "$PATH_BIN_STATD" + + if is_idmapd_enabled; then + kill_process_if_running "$PATH_BIN_IDMAPD" + fi + + if is_nfs3_enabled; then + kill_process_if_running "$PATH_BIN_STATD" + fi + kill_process_if_running "$PATH_BIN_MOUNTD" stop_exportfs kill_process_if_running "$PATH_BIN_RPCBIND" @@ -230,15 +239,28 @@ get_requested_port_statd_out() { is_kerberos_enabled() { if [[ -n "${!ENV_VAR_NFS_ENABLE_KERBEROS}" ]]; then - echo 1 + return 0 fi + + return 1 } is_nfs3_enabled() { if [[ -z "${!ENV_VAR_NFS_DISABLE_VERSION_3}" ]]; then - echo 1 + return 0 fi + + return 1 +} + +is_idmapd_enabled() { + + if [[ "$(get_requested_nfs_version)" != '3' && -f "$PATH_FILE_ETC_IDMAPD_CONF" ]]; then + return 0 + fi + + return 1 } @@ -276,21 +298,19 @@ assert_port() { assert_nfs_version() { - local -r version="$(get_requested_nfs_version)" + local -r requested_version="$(get_requested_nfs_version)" - echo "$version" | grep -Eq '^(3|4|4\.1|4\.2)$' + echo "$requested_version" | grep -Eq '^3|4(?:\.[1-2])?$' on_failure bail "please set $ENV_VAR_NFS_VERSION to one of: 4.2, 4.1, 4, 3" - if [[ -z "$(is_nfs3_enabled)" && "$version" = '3' ]]; then + if [[ ( ! $(is_nfs3_enabled) ) && "$requested_version" = '3' ]]; then bail 'you cannot simultaneously enable and disable NFS version 3' fi } assert_nfsd_threads() { - local -r reqd_thread_count=$(get_requested_count_nfsd_threads) - - if [[ "$reqd_thread_count" -lt 1 ]]; then + if [[ "$(get_requested_count_nfsd_threads)" -lt 1 ]]; then bail "please set $ENV_VAR_NFS_SERVER_THREAD_COUNT to a positive integer" fi } @@ -407,7 +427,7 @@ init_assertions() { assert_linux_capabilities # perform Kerberos assertions - if [[ -n "$(is_kerberos_enabled)" ]]; then + if is_kerberos_enabled; then assert_file_provided "$PATH_FILE_ETC_IDMAPD_CONF" assert_file_provided "$PATH_FILE_ETC_KRB5_KEYTAB" @@ -435,14 +455,14 @@ boot_helper_mount() { boot_helper_get_version_flags() { - local -r reqd_version="$(get_requested_nfs_version)" - local flags=('--nfs-version' "$reqd_version" '--no-nfs-version' 2) + local -r requested_version="$(get_requested_nfs_version)" + local flags=('--nfs-version' "$requested_version" '--no-nfs-version' 2) - if [[ -z "$(is_nfs3_enabled)" ]]; then + if ! is_nfs3_enabled; then flags+=('--no-nfs-version' 3) fi - if [[ "$reqd_version" = '3' ]]; then + if [[ "$requested_version" = '3' ]]; then flags+=('--no-nfs-version' 4) fi @@ -493,7 +513,7 @@ boot_main_rpcbind() { boot_main_idmapd() { - if [[ "$(get_requested_nfs_version)" != '3' && -f "$PATH_FILE_ETC_IDMAPD_CONF" ]]; then + if is_idmapd_enabled; then log 'starting idmapd' $PATH_BIN_IDMAPD -v -S on_failure stop 'idmapd failed' @@ -502,7 +522,7 @@ boot_main_idmapd() { boot_main_statd() { - if [[ -z "$(is_nfs3_enabled)" ]]; then + if ! is_nfs3_enabled; then return fi @@ -527,14 +547,14 @@ boot_main_nfsd() { $PATH_BIN_NFSD "${args[@]}" on_failure stop 'rpc.nfsd failed' - if [ -z "$(is_nfs3_enabled)" ]; then + if ! is_nfs3_enabled; then kill_process_if_running "$PATH_BIN_RPCBIND" fi } boot_main_svcgssd() { - if [[ -z "$(is_kerberos_enabled)" ]]; then + if ! is_kerberos_enabled; then return fi @@ -568,7 +588,7 @@ summarize_nfs_versions() { ;; esac - if [[ -n "$(is_nfs3_enabled)" && "$reqd_version" =~ ^4 ]]; then + if [[ $(is_nfs3_enabled) && "$reqd_version" =~ ^4 ]]; then versions="$versions, 3" fi @@ -598,7 +618,7 @@ summarize_ports() { local -r port_mountd="$(get_requested_port_mountd)" local -r port_statd_in="$(get_requested_port_statd_in)" - if [[ -z "$(is_nfs3_enabled)" ]]; then + if ! is_nfs3_enabled; then log "list of container ports that should be exposed: $port_nfsd (TCP)" else log 'list of container ports that should be exposed:' From 09a73fc044977bbb19483a17b968152e4baa42e5 Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Thu, 27 Sep 2018 12:17:18 -0700 Subject: [PATCH 3/6] grep doesn't do non-capturing groups --- entrypoint.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 5308a60..de58206 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -300,7 +300,7 @@ assert_nfs_version() { local -r requested_version="$(get_requested_nfs_version)" - echo "$requested_version" | grep -Eq '^3|4(?:\.[1-2])?$' + echo "$requested_version" | grep -Eq '^3|4(\.[1-2])?$' on_failure bail "please set $ENV_VAR_NFS_VERSION to one of: 4.2, 4.1, 4, 3" if [[ ( ! $(is_nfs3_enabled) ) && "$requested_version" = '3' ]]; then @@ -636,7 +636,7 @@ summarize_ports() { init() { - log_header 'setting up' + log_header 'setting up ...' init_exports init_assertions @@ -647,7 +647,7 @@ init() { boot() { - log_header 'starting services' + log_header 'starting services ...' boot_main_mounts boot_main_rpcbind From e95afec52308f7de3d5b7aa24f6c6b027a59d26f Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Fri, 26 Oct 2018 14:27:06 -0700 Subject: [PATCH 4/6] initial Alpine support --- CHANGELOG.md | 5 +++++ Dockerfile | 14 +++----------- README.md | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0d1ad..527078a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.0.0] - not yet released + +### Changed + * Switch to Alpine Linux + ## [1.2.0] - 2018-09-26 ### Added diff --git a/Dockerfile b/Dockerfile index e0b59ab..671f6d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,9 @@ -# Alpine can only be used if/when this bug is fixed: https://bugs.alpinelinux.org/issues/8470 -ARG BUILD_FROM=debian:stretch-slim +ARG BUILD_FROM=alpine:latest FROM $BUILD_FROM -# https://github.com/ehough/docker-nfs-server/pull/3#issuecomment-387880692 -ARG DEBIAN_FRONTEND=noninteractive - -# kmod is needed for lsmod, and libcap2-bin is needed for confirming Linux capabilities -RUN apt-get update && \ - apt-get install -y --no-install-recommends nfs-kernel-server kmod libcap2-bin && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists && \ - \ +RUN apk --update --no-cache add bash nfs-utils && \ + \ # remove the default config files rm -v /etc/idmapd.conf /etc/exports diff --git a/README.md b/README.md index fb5c96c..21577f7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ A lightweight, robust, flexible, and containerized NFS server. This is the only containerized NFS server that offers **all** of the following features: - NFS versions 3, 4, or both simultaneously +- small (< 15MB) Alpine Linux image - clean teardown of services upon termination (no lingering `nfsd` processes on Docker host) - flexible construction of `/etc/exports` - extensive server configuration via environment variables @@ -153,7 +154,6 @@ Please [open an issue](https://github.com/ehough/docker-nfs-server/issues) if yo ## Remaining tasks -- switch to Alpine Linux once `nfs-utils` version 2.3.1-r4 (or higher) is released in a stable repo (maybe Alpine 3.9?). See [this bug](https://bugs.alpinelinux.org/issues/8470) for details - figure out why `rpc.nfsd` takes 5 minutes to startup/timeout unless `rpcbind` is running - add more examples, including Docker Compose From 8e2ee49538140b93613b4b39e47534c343be19e0 Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Thu, 31 Jan 2019 12:54:35 -0800 Subject: [PATCH 5/6] loose ends before switch to Alpine --- Dockerfile | 4 ++-- README.md | 28 ++++++++++++++-------------- entrypoint.sh | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 671f6d5..ca4b24f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,8 +8,8 @@ RUN apk --update --no-cache add bash nfs-utils && \ rm -v /etc/idmapd.conf /etc/exports # http://wiki.linux-nfs.org/wiki/index.php/Nfsv4_configuration -RUN mkdir -p /var/lib/nfs/rpc_pipefs && \ - mkdir -p /var/lib/nfs/v4recovery && \ +RUN mkdir -p /var/lib/nfs/rpc_pipefs && \ + mkdir -p /var/lib/nfs/v4recovery && \ echo "rpc_pipefs /var/lib/nfs/rpc_pipefs rpc_pipefs defaults 0 0" >> /etc/fstab && \ echo "nfsd /proc/fs/nfsd nfsd defaults 0 0" >> /etc/fstab diff --git a/README.md b/README.md index 21577f7..e80ceaf 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ A lightweight, robust, flexible, and containerized NFS server. This is the only containerized NFS server that offers **all** of the following features: +- small (~15MB) Alpine Linux image - NFS versions 3, 4, or both simultaneously -- small (< 15MB) Alpine Linux image - clean teardown of services upon termination (no lingering `nfsd` processes on Docker host) - flexible construction of `/etc/exports` - extensive server configuration via environment variables @@ -40,7 +40,7 @@ This is the only containerized NFS server that offers **all** of the following f - `nfs` - `nfsd` - `rpcsec_gss_krb5` (*only if Kerberos is used*) - + Usually you can enable these modules with: `modprobe {nfs,nfsd,rpcsec_gss_krb5}` 1. The container will need to run with `CAP_SYS_ADMIN` (or `--privileged`). This is necessary as the server needs to mount several filesystems *inside* the container to support its operation, and performing mounts from inside a container is impossible without these capabilities. 1. The container will need local access to the files you'd like to serve via NFS. You can use Docker volumes, bind mounts, files baked into a custom image, or virtually any other means of supplying files to a Docker container. @@ -57,13 +57,13 @@ Starting the `erichough/nfs-server` image will launch an NFS server. You'll need --cap-add SYS_ADMIN \ -p 2049:2049 \ erichough/nfs-server - + Let's break that command down into its individual pieces to see what's required for a successful server startup. 1. **Provide the files to be shared over NFS** As noted in the [requirements](#requirements), the container will need local access to the files you'd like to share over NFS. Some ideas for supplying these files: - + * [bind mounts](https://docs.docker.com/storage/bind-mounts/) (`-v /host/path/to/shared/files:/some/container/path`) * [volumes](https://docs.docker.com/storage/volumes/) (`-v some_volume:/some/container/path`) * files [baked into](https://docs.docker.com/engine/reference/builder/#copy) custom image (e.g. in a `Dockerfile`: `COPY /host/files /some/container/path`) @@ -80,7 +80,7 @@ Let's break that command down into its individual pieces to see what's required -v /host/path/to/exports.txt:/etc/exports:ro \ ... \ erichough/nfs-server - + 1. provide each line of `/etc/exports` as an environment variable The container will look for environment variables that start with `NFS_EXPORT_` and end with an integer. e.g. `NFS_EXPORT_0`, `NFS_EXPORT_1`, etc. @@ -103,13 +103,13 @@ Let's break that command down into its individual pieces to see what's required 1. **Use `--cap-add SYS_ADMIN` or `--privileged`** As noted in the [requirements](#requirements), the container will need additional privileges. So your `run` command will need *either*: - + docker run --cap-add SYS_ADMIN ... erichough/nfs-server or - + docker run --privileged ... erichough/nfs-server - + Not sure which to use? Go for `--cap-add SYS_ADMIN` as it's the lesser of two evils. 1. **Expose the server ports** @@ -117,11 +117,11 @@ Let's break that command down into its individual pieces to see what's required You'll need to open up at least one server port for your client connections. The ports listed in the examples below are the defaults used by this image and most can be [customized](doc/ports.md). * If your clients connect via **NFSv4 only**, you can get by with just TCP port `2049`: - + docker run -p 2049:2049 ... erichough/nfs-server - + * If you'd like to support **NFSv3**, you'll need to expose a lot more ports: - + docker run \ -p 2049:2049 -p 2049:2049/udp \ -p 111:111 -p 111:111/udp \ @@ -129,9 +129,9 @@ Let's break that command down into its individual pieces to see what's required -p 32767:32767 -p 32767:32767/udp \ ... \ erichough/nfs-server - + If you pay close attention to each of the items in this section, the server should start quickly and be ready to accept your NFS clients. - + ### Mounting filesystems from a client # mount :/some/export /some/local/path @@ -141,7 +141,7 @@ If you pay close attention to each of the items in this section, the server shou * [Kerberos security](doc/feature/kerberos.md) * [NFSv4 user ID mapping](doc/feature/nfs4-user-id-mapping.md) * [AppArmor integration](doc/feature/apparmor.md) - + ## Advanced * [customizing which ports are used](doc/advanced/ports.md) diff --git a/entrypoint.sh b/entrypoint.sh index de58206..fb92484 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -303,7 +303,7 @@ assert_nfs_version() { echo "$requested_version" | grep -Eq '^3|4(\.[1-2])?$' on_failure bail "please set $ENV_VAR_NFS_VERSION to one of: 4.2, 4.1, 4, 3" - if [[ ( ! $(is_nfs3_enabled) ) && "$requested_version" = '3' ]]; then + if [[ ( ! is_nfs3_enabled ) && "$requested_version" = '3' ]]; then bail 'you cannot simultaneously enable and disable NFS version 3' fi } @@ -541,7 +541,7 @@ boot_main_nfsd() { read -r -a version_flags <<< "$(boot_helper_get_version_flags)" local -r threads=$(get_requested_count_nfsd_threads) local -r port=$(get_requested_port_nfsd) - local -r args=('--debug' 8 '--port' "$port" "${version_flags[@]}" "$threads") + local -r args=('--debug' 8 '--tcp' '--udp' '--port' "$port" "${version_flags[@]}" "$threads") log "starting rpc.nfsd on port $port with $threads server thread(s)" $PATH_BIN_NFSD "${args[@]}" @@ -588,7 +588,7 @@ summarize_nfs_versions() { ;; esac - if [[ $(is_nfs3_enabled) && "$reqd_version" =~ ^4 ]]; then + if [[ is_nfs3_enabled && "$reqd_version" =~ ^4 ]]; then versions="$versions, 3" fi From 43808e166a8f4ec35a0f9233fe6ceaed90d1f899 Mon Sep 17 00:00:00 2001 From: Eric Hough Date: Thu, 31 Jan 2019 12:56:17 -0800 Subject: [PATCH 6/6] update changelog for 2.0.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 527078a..6ad2efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [2.0.0] - not yet released +## [2.0.0] - 2019-01-31 ### Changed * Switch to Alpine Linux