【问题标题】:Running OpenSSH in an Alpine Docker Container在 Alpine Docker 容器中运行 OpenSSH
【发布时间】:2016-06-11 23:37:53
【问题描述】:

我有installed OpenSSH,现在我希望通过运行/etc/init.d/sshd start 来按照documentation 中的描述运行它。但是它没有启动:

 / # /etc/init.d/sshd start
 /bin/ash: /etc/init.d/sshd: not found

想法?

附:

/ # ls -la /etc/init.d/sshd 
-rwxr-xr-x    1 root     root          2622 Jan 14 20:48 /etc/init.d/sshd

/etc/init.d/sshd的内容:

    #!/sbin/openrc-run
    # Copyright 1999-2015 Gentoo Foundation
    # Distributed under the terms of the GNU General Public License v2
    # $Header: /var/cvsroot/gentoo-x86/net-misc/openssh/files/sshd.rc6.4,v 1.5 2015/05/04 02:56:25 vapier Exp $

    description="OpenBSD Secure Shell server"
    description_checkconfig="Verify configuration file"
    description_reload="Reload configuration"

    extra_commands="checkconfig"
    extra_started_commands="reload"

    : ${SSHD_CONFDIR:=/etc/ssh}
    : ${SSHD_CONFIG:=${SSHD_CONFDIR}/sshd_config}
    : ${SSHD_PIDFILE:=/var/run/${SVCNAME}.pid}
    : ${SSHD_BINARY:=/usr/sbin/sshd}

    depend() {
        use logger dns
        if [ "${rc_need+set}" = "set" ] ; then
            : # Do nothing, the user has explicitly set rc_need
        else
            local x warn_addr
            for x in $(awk '/^ListenAddress/{ print $2 }' "$SSHD_CONFIG" 2>/dev/null) ; do
                case "${x}" in
                    0.0.0.0|0.0.0.0:*) ;;
                    ::|\[::\]*) ;;
                    *) warn_addr="${warn_addr} ${x}" ;;
                esac
            done
            if [ -n "${warn_addr}" ] ; then
                need net
                ewarn "You are binding an interface in ListenAddress statement in your sshd_config!"
                ewarn "You must add rc_need=\"net.FOO\" to your /etc/conf.d/sshd"
                ewarn "where FOO is the interface(s) providing the following address(es):"
                ewarn "${warn_addr}"
            fi
        fi
    }

    checkconfig() {
        if [ ! -d /var/empty ] ; then
            mkdir -p /var/empty || return 1
        fi

        if [ ! -e "${SSHD_CONFIG}" ] ; then
            eerror "You need an ${SSHD_CONFIG} file to run sshd"
            eerror "There is a sample file in /usr/share/doc/openssh"
            return 1
        fi

        if ! yesno "${SSHD_DISABLE_KEYGEN}"; then
            ssh-keygen -A || return 1
        fi

        [ "${SSHD_PIDFILE}" != "/var/run/sshd.pid" ] \
            && SSHD_OPTS="${SSHD_OPTS} -o PidFile=${SSHD_PIDFILE}"
        [ "${SSHD_CONFIG}" != "/etc/ssh/sshd_config" ] \
            && SSHD_OPTS="${SSHD_OPTS} -f ${SSHD_CONFIG}"

        "${SSHD_BINARY}" -t ${SSHD_OPTS} || return 1
    }

    start() {
        checkconfig || return 1

        ebegin "Starting ${SVCNAME}"
        start-stop-daemon --start --exec "${SSHD_BINARY}" \
            --pidfile "${SSHD_PIDFILE}" \
            -- ${SSHD_OPTS}
        eend $?
    }

    stop() {
        if [ "${RC_CMD}" = "restart" ] ; then
            checkconfig || return 1
        fi

        ebegin "Stopping ${SVCNAME}"
        start-stop-daemon --stop --exec "${SSHD_BINARY}" \
            --pidfile "${SSHD_PIDFILE}" --quiet
        eend $?

        if [ "$RC_RUNLEVEL" = "shutdown" ]; then
            _sshd_pids=$(pgrep "${SSHD_BINARY##*/}")
            if [ -n "$_sshd_pids" ]; then
                ebegin "Shutting down ssh connections"
                kill -TERM $_sshd_pids >/dev/null 2>&1
                eend 0
            fi
        fi
    }

    reload() {
        checkconfig || return 1
        ebegin "Reloading ${SVCNAME}"
        start-stop-daemon --signal HUP \
            --exec "${SSHD_BINARY}" --pidfile "${SSHD_PIDFILE}"
        eend $?
    }

【问题讨论】:

  • 请您尝试安装openssh-server by sudo apt-get install openssh-server
  • 这是一个 Alpine Linux 容器,它使用 apk 包管理器。有关详细信息,请参阅文档链接。
  • 然后apk add openssh-server。添加 openssh-server 在 Debian 系统中有效。所以只是一个想法。
  • which sshd 返回什么?
  • / # 哪个 sshd --- 返回 >>> /usr/sbin/sshd

标签: linux shell docker openssh alpine


【解决方案1】:

容器不是完整安装的环境。 官方文档适用于在某些机器上安装的 alpine。 具有容器所没有的上电、启动服务等。

因此,/etc/init.d/ 中的任何内容都不能直接在启动服务使用的容器中使用(如 systemd 或 alpine 的 rc*)。这就是您收到错误消息的原因,原因是容器中未安装 rc*

您需要做的是手动启动 sshd。 你可以看看下面的例子:

https://hub.docker.com/r/danielguerra/alpine-sshd/~/dockerfile/

【讨论】:

  • 据我了解,示例脚本只能运行 sshd,不能运行任何其他命令。无论你指定什么命令,你如何让它变成 sshd + 另一个应用程序?
  • 仅链接答案 :(
  • @FreeSoftwareServers 可能点击链接对你来说太难了 :)
  • @CSJ 我认为作为一个更高代表的用户你会更清楚,但避免 Link_Rot 是不好的 --> en.wikipedia.org/wiki/Link_rot
【解决方案2】:

/etc/init.d/sshd: 未找到

尝试运行这些命令:

apk add --no-cache openrc
rc-update add sshd

【讨论】:

    【解决方案3】:

    尽管有些细节我还不清楚,让我在讨论中发言。以下配置指定的解决方案对我有用。这是艰苦实验的结果。

    首先,dockerfile

    FROM alpine
    RUN apk update && \
    apk add --no-cache sudo bash openrc openssh
    RUN mkdir -p /run/openrc && \
        touch /run/openrc/softlevel && \
        rc-update add sshd default
    RUN adduser --disabled-password regusr && \
        sh -c 'echo "regusr:<encoded_passwd>"' | chpasswd -e > /dev/null 2>&1 && \
        sh -c 'echo "regusr ALL=NOPASSWD: ALL"' >> /etc/sudoers
    VOLUME ["/home/reguser/solution/entrypoint-init.d","/sys/fs/cgroup"]
    USER reguser
    WORKDIR /home/reguser
    RUN mkdir -p $HOME/solution && sudo chown reguser:reguser $HOME/solution
    ADD ./entrypoint.sh /home/reguser/solution/
    EXPOSE 22
    ENTRYPOINT ["./solution/entrypoint.sh"]
    CMD ["/bin/bash"]
    

    接下来,/home/reguser/solution/entrypoint.sh

    #!/bin/bash
    for f in ./solution/entrypoint-init.d/*; do
        case "$f" in
           *.sh)     echo "$0: running $f"; . "$f" ;;
           *)        echo "$0: ignoring $f" ;;
        esac
        echo
    done
    
    exec "$@"
    

    接下来,/home/reguser/solution/entrypoint-init.d/10-ssh-up.sh

    #!/bin/bash
    sudo sed --in-place --expression='/^#[[:space:]]*Port[[:space:]]\+22$/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^#[[:space:]]*AddressFamily[[:space:]]\+any$/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^#[[:space:]]*HostKey[[:space:]]\+\/etc\/ssh\/ssh_host_rsa_key$/ s/^#//i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='/^#[[:space:]]*HostbasedAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*HostbasedAuthentication[[:space:]].*/ s/^[[:space:]]*\(HostbasedAuthentication\)[[:space:]]\(.*\)/\1 no/i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*HostbasedAuthentication[[:space:]]\+yes.*/ s/^/#/i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='/^#[[:space:]]*IgnoreRhosts[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*IgnoreRhosts[[:space:]].*/ s/^[[:space:]]*\(IgnoreRhosts\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*IgnoreRhosts[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='/^#[[:space:]]*PasswordAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PasswordAuthentication[[:space:]].*/ s/^[[:space:]]*\(PasswordAuthentication\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PasswordAuthentication[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='/^#[[:space:]]*PubkeyAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PubkeyAuthentication[[:space:]].*/ s/^[[:space:]]*\(PubkeyAuthentication\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PubkeyAuthentication[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='/^#[[:space:]]*PrintMotd[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PrintMotd[[:space:]].*/ s/^[[:space:]]*\(PrintMOTD\)[[:space:]]\(.*\)/\1 no/i' -- /etc/ssh/sshd_config
    sudo sed --in-place --expression='/^[[:space:]]*PrintMotd[[:space:]]\+yes.*/ s/^/#/i' -- /etc/ssh/sshd_config
    
    sudo sed --in-place --expression='$ a\' --expression='\nAcceptEnv LANG LC_\*' -- /etc/ssh/sshd_config
    
    sudo /etc/init.d/sshd --dry-run start
    sudo /etc/init.d/sshd start
    

    最后两行是诀窍的核心。特别是,sudo /etc/init.d/sshd --dry-run start 使解决方案有效。

    最后是命令行控件

    docker build --tag='dockerRegUser/sshdImg:0.0.1' --file='./dockerfile' .
    docker container create --tty \
           --volume $(pwd)/dock/entrypoint-init.d:/home/reguser/solution/entrypoint-init.d:ro \
           --name sshdCnt 'dockerRegUser/sshdImg:0.0.1' tail -f /dev/null
    docker start sshdCnt && \
    ssh-keygen -f "/home/user/.ssh/known_hosts" -R "$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' sshdCnt)" && \
    sleep 5 && \
    ssh-copy-id -i ~/.ssh/sshkey reguser@$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' sshdCnt)
    

    我知道,我知道,有很多不必要的结构。该示例也违反了单服务 docker 容器原则。但是在解决方案开发和交付生命周期中的某些阶段和情况证明(或至少是诱人的)考虑使用 sshd 或其他 openrc 控制的服务扩展容器是合理的。

    【讨论】:

      【解决方案4】:

      首先检查/usr/bin/usr/sbin 中是否不存在sshd。

      那么,init.d 只有在你设置为自动启动时才应该有 sshd:

      rc-update add sshd
      rc-status
      

      【讨论】:

      • 现在是usr/sbin。同样运行rc-update 会导致/bin/ash: rc-update: not found
      • 运行时我得到相同的结果 >>> / # /usr/bin/sshd start /bin/ash: /usr/bin/sshd: not found
      • 我看到sshd的大小比较小。是脚本吗?你能打开它看看它是否引用了不存在的路径吗?
      • 我粘贴的/etc/init.d/sshd in the question. The contents of /bin/sbin/sshd的内容是二进制的。
      • 否 - 顺便说一句 - @VonC 你可以启动一个容器并看起来像这样: docker run -it --rm alpine /bin/ash
      【解决方案5】:

      出于一个非常具体的原因,我需要sshd。我必须在 CI 服务器上运行前端 (cypress) 和后端 (django) 端测试。至少在一个容器中运行它们很棘手,所以我决定使用 2 个容器。此外,必须有一个入口点可以在两个容器中运行测试。因此,想法是一个容器将运行它的测试,而不是通过 ssh 在另一个容器中运行测试。

      在您的情况下,您可能不想像我一样做,例如设置空的root密码,空的密码。

      最好在单独的目录中运行它,因为它会创建文件 (id_rsa.pub)。

      server.sh:

      #!/bin/sh -eux
      apk add openssh-server
      ssh-keygen -A
      passwd -d root
      mkdir ~/.ssh
      while ! [ -e id_rsa.pub ]; do sleep 1; done
      cp id_rsa.pub ~/.ssh/authorized_keys
      /usr/sbin/sshd -De
      

      client.sh:

      #!/bin/sh -eux
      apk add openssh-client wait4ports
      ssh-keygen -f ~/.ssh/id_rsa -N ''
      cp ~/.ssh/id_rsa.pub .
      wait4ports -s 1 tcp://c1:22
      ssh-keyscan -t rsa c1 > ~/.ssh/known_hosts
      ssh c1 echo DO SOMETHING
      echo done
      

      docker-compose.yml:

      version: '3'
      services:
          server:
              image: alpine:3.12
              command: sh -c 'cd app && ./server.sh'
              volumes:
                  - .:/app
          client:
              image: alpine:3.12
              command: sh -c 'cd app && ./client.sh'
              volumes:
                  - .:/app
      
      $ docker-compose up -d && docker-compose logs -f
      

      如果您决定再次运行它:

      $ rm -f id_rsa.pub && docker-compose down && docker-compose up -d && docker-compose logs -f
      

      【讨论】:

        【解决方案6】:

        如果你想用 alpine 在你的 docker 容器上设置 openssh 服务器,试试这个 Dockerfile。

        在本例中,我使用的是docker:dind 图像

        FROM docker:dind
        # Setup SSH Service
        RUN \
          apk update && \
          apk add openrc --no-cache && \
          apk add openssh-server && \
          rc-update add sshd && \
          rc-status && \
          touch /run/openrc/softlevel 
        
        # Expose port for ssh
        EXPOSE 22
        
        # Start SSH Service
        CMD ["sh" , "-c", "service sshd restart && sh"]
        

        一旦您的容器启动并运行,请尝试运行此命令以确保 ssh 正常工作:

        ssh localhost
        

        【讨论】:

          猜你喜欢
          • 2016-06-11
          • 1970-01-01
          • 1970-01-01
          • 2018-04-09
          • 2017-12-01
          • 1970-01-01
          • 2021-09-27
          • 2019-05-26
          • 1970-01-01
          相关资源
          最近更新 更多