在Docker容器中不需要运行sshd的原因浅析

当开始使用Docker时,人们经常问:“我该如何进入容器?”,其他人会说“在你的容器里运行一个SSH服务器”。但是,从这篇博文中你将会了解到你根本不需要运行SSHd守护进程来进入你的容器。当然,除非你的容器就是一个SSH服务器。

运行SSH服务器是很想当然的,因为它提供了进入容器的简便方式。在我们公司基本上每个人都最少使用过一次SSH。我们中有很大一部分人每天都会使用它,并且他们很熟悉公钥与私钥,无密码登录,密钥代理,甚至有时会使用端口转发和其他不常用的功能。正因如此,人们建议你在容器中运行SSH并不奇怪。但你应该仔细考虑下。

假设你正在假设一个Redis Server或Java Webservice的Docker镜像, 我会问你以下几个问题:

你需要用SSH来做什么? 一般来说, 你想做备份, 检查日志, 或者重启进程, 调整配置, 还有可能用gdb, strace或其他类似的工具来debug服务器。那我们会看一下我们怎么不使用SSH来做这些事情。

你怎么管理你的密钥和密码的?一般来说,你要么把它们写到你的镜像中,要么就把它们放在一个卷中。你想一下如果你要更新这些密钥或密码你会怎么做呢。如果你把它们写到镜像里了,你就需要重建镜像,重新部署它们,然后重启容器。这还好,不算是世界末日,但是这绝不是一个高大上的方法。把它们放到卷中,然后通过管理卷来管理它们倒是比前一种好得多。这种方法是可用的,可是却有严重的缺陷。你必须要确认容器没有这个卷的写权限;否则,容器有可能会破坏密钥(这让你之后就进不去容器了),如果你再用一个卷共享给多个容器的话,情况会变得更糟。如果不用SSH,我们不就少一个需要担心的事了吗?

你如何管理安全升级呢?SSH服务器是挺安全的,但是仍然会有安全问题,你会在必要的时候不得不升级所有使用SSH的容器。这意味着大量的重建和重启。也就是说,及时你有一个简单小巧的memcached服务,你还是不得不确保及时的安全更新,否则千里之堤可能毁于蚁穴。所以还是这句话,如果不用SSH,我们不就少一个需要担心的事了吗?

你需要“仅安装一个SSH服务器”来达到目的吗?当然不。你需要加装进程管理器,比如Monit或者Supervisor。这是因为Docker自己只会监视一个进程。如果你需要运行多个进程,你就必须在上面加装一层可以看着他们的应用。换句话说,你在把简单问题复杂化。如果你的应用停了(正常退出或者崩溃),你必须要从你的进程管理日志里面去查看,而不能简单的查看Docker提供的信息。

你可以负责把应用放到容器中,但你是否应该同时负责管理访问策略和安全限制呢?在小机构中,这都不是事。但是在大型机构中,如果你是负责设立应用容器的人,那很可能有另外一个人负责定义远程访问策略。你所在的公司很可能有严格的策略定义说明谁能访问,如何访问或者其他各种审查跟踪的要求。那样的话,你肯定不会被允许把一个SSH服务器扔进你的容器中。

但我该如何做…

备份我的数据?

你的数据应该存在于 volume中. 然后你可以使用--volumes-from选项来运行另一个容器,与第一个容器共享这个volume。这样做的好处:如果你需要安装新的工具(如s75pxd)来将你备份的数据长期保存,或将数据转移到其他永久存储时,你可以在这个特定的备份容器中进行,而不是在主服务容器中。这很简洁。

检查日志?

再次使用 volume! 如果你将所有日志写入一个特定的目录下,且这个目录是一个volume的话,那你可以启动另一个log inspection" 容器(使用--volumes-from,还记得么?)且在这里面做你需要做的事。如果你还需要特殊的工具(或只需要一个有意思的ack-grep),你可以在这个容器中安装它们,这样可以保持主容器的原始环境。

重启service?

基本上所有service都可以通过信号来重启。当你使用/etc/init.d/foo restart或service foo restart时,实际上它们都会给进程发送一个特定的信号。你可以使用docker kill -s <signal>来发送这个信号。一些service可能不会监听这些信号,但可以在一个特定的socket上接受命令。如果是一个TCP socket,只需要通过网络连接上就可以了。如果是一个UNIX套接字,你可以再次使用volume。将容器和service的控制套接字设置到一个特定的目录中,且这个目录是一个volume。然后启动一个新的容器来访问这个volume;这样就可以使用UNIX套接字了。

“但这也太复杂了吧!”-其实不然。假设你名为foo的servcie 在/var/run/foo.sock创建了一个套接字,且需要你运行fooctl restart来完成重启。只需要使用-v /var/run(或在Docker文件中添加VOLUME /var/run)来启动这个service就可以了。当你想重启的时候,使用--volumes-from选项并重载命令来启动相同的镜像。像这样:

# Starting the service
CID=$(docker run -d -v /var/run fooservice)
# Restarting the service with a sidekick container
docker run --volumes-from $CID fooservice fooctl restart 

很简单吧!

修改我的配置文件

如果你正在执行一个持久的配置变更,你最好把他的改变放在image中,因为如果你又启动一个container,那么服务还是使用的老的配置,你的配置变更将丢失。所以,没有您的SSH访问!“但是我需要在服务存活期间,改变我的配置;例如增加一个新的虚拟站点!”这种情况下,你需要使用……等待……volume!配置应该在volume中,并且该volume应该和一个特殊目的“配置编辑器”容器共享。你可以在这个容器中使用任何你喜欢的东西:SSH + 你最喜欢的编辑器,或一个接受API调用的web服务,或一个从外部源抓取信息的定时任务;诸如此类。另外,分离关注:一个容器运行服务,另外一个处理配置更新。“但是我做临时更改,因为我正在测试不同的值!”在这种情况下,查看下一章节!

调试我的应用?

这可能是唯一需要进入container的场景了。因为你要运行gdb, strace, tweak配置,等。这种情况下,你需要 nsenter。

介绍 nsenter

nsenter是一个小的工具,用来进入命名空间中。技术上,它可以进入现有的命名空间,或者产生一个进程进入新的一组命名空间。“命名空间是什么?”他们是容器的重要组成部分。简单点说:通过使用 nsenter ,你可以进入一个已经存在的container中,尽管这个container没有运行ssh 或者任意特殊用途的守护进程。

从哪里获得 nsenter ?

在GitHub上查看 jpetazzo/nsenter 。简单的安装是:

docker run -v /usr/local/bin:/target jpetazzo/nsenter 

它将会把 nsenter 安装到 /usr/local/bin 中,你就可以立刻使用它了。

nsenter 也可以在你的发行版中获得(在 util-linux 包中)。

如何使用?

首先,计算出你要进入容器的PID:

PID=$(docker inspect --format {{.State.Pid}} <container_name_or_ID>) 

然后进入容器:

nsenter --target $PID --mount --uts --ipc --net --pid 

在容器里,可以操作shell解析器。如果要想以自动化的方式来运行特殊的脚本或程序,把它作为参数添加到nsenter中。除了它使用容器代替了简单目录来工作外,它的工作方式有点像chroot。

远程访问怎么样?

如果你需要从一个远程主机进入一个容器,有(至少)两个方法:

SSH 进入 Docker 主机,并使用 nsenter;

SSH 进入 Docker 主机,通过一个特殊的密钥参数授权esenter命令 (也就是,nsenter)。

第一种方法相对简单;但是需要root权限访问Docker主机(从安全角度来说不是很好)。第二种方法在 SSH 的 authorized_keys 文件中使用 command= 模式。你可能熟悉 “古典的” authorized_keys文件,它看起来像这样:

ssh-rsa AAAAB3N…QOID== jpetazzo@tarrasque

(当然,实际上一个真正的密钥是很长的,一般都会占据好几行。)你也可以强制使用一个专有的命令。如果你想要在你的系统上查看一个远程的主机上可以有效使用的内存,可以使用SSH密钥,但是你不会希望交出所有的shell权限,你可以在authorized_keys文件中输入下面的内容:

command="free" ssh-rsa AAAAB3N…QOID== jpetazzo@tarrasque 

现在,当使用专有的密钥进行连接时,替换取得的shell,它可以执行free命令。除此之外,就不能做其他的。(通常,你可能还想要添加no-port-forwarding;如果希望了解更多信息可以查看authorized_keys(5)的手册(manpage))。这种机制的关键是使得责任分离。Alice把服务放在容器内部;她不用处理远程的访问,登陆等事务。Betty会添加SSH层,在特殊情况(调试奇怪的问题)下使用。Charlotte会考虑登陆。等等。

总结

在一个容器中运行SSH服务器,这真的是一个错误(大写字母W)吗?老实说,没那么严重。当你不去访问Docker主机的时候,这样做甚至是极其方便的,但是这仍然需要在容器中取得一个shell。除此之外,我们还有许多方式可以在容器中运行SSH服务器,并能取得所有我们想要的特性,而且其架构还非常清晰。Docker允许你使用任何最适合你的工作流。但是,在做这些之前,迅速步入“我的容器真的是一个小的VPS”这句流行语的(语境)时,请注意还有其他的解决方案,这样你才可以做出一个明智的决定。

以上所述是小编给大家介绍的在Docker容器中不需要运行sshd的原因浅析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 详解docker 允许主机ssh连接到docker容器中

    在docker容器中,安装好ssh: 1)替换掉容器中的安装源为163源 2)安装ssh服务 apt-get update apt-get install openssh-server 3)添加目录,修改ssh配置文件 mkdir -p /var/run/sshd vim /etc/pam.d/sshd 找到 session    required     pam_loginuid.so 这一行,将它注释掉 4)添加要链接过来的主机公钥 将公钥放到/root/.ssh/authorized_ke

  • docker centos7 安装ssh具体步骤

     docker centos7 安装ssh具体步骤,这里记录下,也行能帮助到正在读文章的朋友. 一. 从docker hub 下载centos 官方镜像 hr:centos7 hr$ docker pull centos:7 下载完后,查看本地资源库: hr:centos7 hr$ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos 7 ce20c473cd8a 7 weeks ago 172.3 MB 运行容器 h

  • Docker使用Dockerfile创建支持ssh服务自启动的容器镜像

    本文实例为大家分享了Dockerfile创建支持ssh服务自启动的容器镜像,供大家参考,具体内容如下 1. 首先创建一个Dockerfile文件,文件内容如下 # 选择一个已有的os镜像作为基础 FROM centos:centos6 # 镜像的作者 MAINTAINER Fanbin Kong "kongxx@hotmail.com" # 安装openssh-server和sudo软件包,并且将sshd的UsePAM参数设置成no RUN yum install -y openssh

  • docker容器里安装ssh的具体步骤

    docker安装ssh 通过命令行安装 1.pull ubuntu镜像 docker pull ubuntu:latest 2.启动并进入bash docker run -it -d ubuntu:lastest /bin/bash # 查看刚刚运行容器的id docker ps # 在容器中执行bash命令 docker exec -it id /bin/bash 3.安装openssh-server并启动 apt-get update apt-get install openssh-serv

  • CentOS 6.5 制作可以ssh登录的Docker镜像

    Docker使用系列一我们把镜像源改为了阿里云的,方便后续的操作. 执行这个命令就把源地址改为阿里的: 复制代码 代码如下: curl https://git.oschina.net/feedao/Docker_shell/raw/start/ali-centos.sh | sh 第一安装Docker: yum -y install docker-io 第二启动Docker: service docker start 第三安装制作CentOS镜像的工具: yum -y install feboo

  • 详解Docker创建支持ssh服务的容器和镜像

    1. 这里使用的centos作为容器,所以首先下载centos的images # sudo docker pull centos 2. 下载后运行一个centos的容器,这里使用centos6作为我测试的容器 # sudo docker run --name=centos-ssh -i -t centos:centos6 /bin/bash  3. 安装openssh-server服务软件包 # yum install openssh-server 4. 编辑sshd的配置文件/etc/ssh/

  • 在Docker容器中不需要运行sshd的原因浅析

    当开始使用Docker时,人们经常问:"我该如何进入容器?",其他人会说"在你的容器里运行一个SSH服务器".但是,从这篇博文中你将会了解到你根本不需要运行SSHd守护进程来进入你的容器.当然,除非你的容器就是一个SSH服务器. 运行SSH服务器是很想当然的,因为它提供了进入容器的简便方式.在我们公司基本上每个人都最少使用过一次SSH.我们中有很大一部分人每天都会使用它,并且他们很熟悉公钥与私钥,无密码登录,密钥代理,甚至有时会使用端口转发和其他不常用的功能.正因如

  • Docker容器中运行flume及启动不输出运行日志问题

    flume配置文件如下: # Name the components on this agent app1.sources = r1 app1.sinks = k1 app1.channels = c1 # Describe/configure the source app1.sources.r1.type = avro app1.sources.r1.bind = 0.0.0.0 app1.sources.r1.port = 44444 # Describe the sink #a1.sink

  • 在 Docker 容器中运行 PHPMyAdmin的详细步骤

    目录 基本用法 预设服务器 使用 MySQL Docker 容器 使用 Docker Compose 简化部署 配置安装 概括 PHPMyAdmin是 MySQL 和 MariaDB 数据库的流行管理界面.它允许您使用 Web 浏览器与您的模式.表和数据进行交互.phpMyAdmin能够为你的MySQL提供直观.方便的Web管理界面,非常好用. 该项目有一个官方的 Docker 镜像,它简化了在容器化环境中的部署.以下是如何使用图像快速运行新的 PHPMyAdmin 实例. 基本用法 最简单的安

  • 详解挂载运行的docker容器中如何挂载文件系统

    前言 感觉最近很多人都在问docker相关的问题,关于怎么操作一个已经启动的docker容器的文件系统,首先我发现这非常困难,因为 mnt的命名空间. 为了登录进入一个已经启动的docker容器,我们需要这么做: 使用nsenter来在临时挂载点上挂载整个docker容器的文件系统. 创建一个特定目录的绑定挂载来当作卷来使用. 卸载临时挂载. 好吧,开始实践. 启动一个名为charlie的docker实例: $ docker run --name charlie -ti ubuntu bash

  • 详解如何在 docker 容器中捕获信号

    我们可能都使用过 docker stop 命令来停止正在运行的容器,有时可能会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过从主机向容器发送信号实现主机与容器中程序的交互.比如我们可以向容器中的应用发送一个重新加载信号,容器中的应用程序在接到信号后执行相应的处理程序完成重新加载配置文件的任务.本文将介绍在 docker 容器中捕获信号的基本知识. 信号(linux) 信号是一种进程间通信的形式.一个信号就是内核发送给进程的一个消息,告诉进程

  • nginx在docker容器中自动生成配置文件

    公司在搭建docker自动化部署时,需要制作一个nginx镜像在其docker run时通过外部指定环境变量使得容器中的配置文件自动生成,不需要再到容器里改配置文件. 实现思路 最后运行的命令大概是这样: docker run -d -p 80:80 -e xxx=xx 镜像名称 镜像中脚本路径 这里的脚本会代替dockerfile中的CMD指令,所以我们要构建一个自动生成且启动nginx的shell脚本. #!/bin/bash #从环境变量里面获取lt开头,为了与其他环境变量区别开,例如lt

  • 如何隔离docker容器中的用户的方法

    笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果你已经了解了 Linux 的 user namespace 技术(参考<Linux Namespace : User>),那么自然会问:docker 为什么不利用 Linux user namespace 实现用户的隔离呢?事实上,docker 已经实现了相关的功能,只是默认没有启用而已.笔者将在

  • 详解如何将Spring Boot应用跑在Docker容器中

    日常的Rest服务开发我都会首选SpringBoot,因为它本身的易用性以及自带的各种方便功能.生态等,今天就简单讲一下如何将Spring Boot应用跑在Docker容器中 项目搭建 首先打开Idea,选择初始化一个Spring Boot应用,然后一路回车下去,待Idea下载完依赖,开始编码 这里写一个简单的接口: @RestController @SpringBootApplication public class DemoApplication { @GetMapping("/hello&

  • docker容器中切换用户,提示权限不足的解决

    docker容器中切换用户,提示权限不足: 解决办法: 启动容器是使用特权启动: docker run -i -t --privileged -v /home/dora:/home/dora centos_ora /bin/bash 补充知识:linux下docker使用普通权限运行 linux下安装docker默认会安装为名为docker的用户才能运行的权限,使用时需要切换用户,很不方便 为了直接使用命令,需要将当前用户加入docker组 sudo usermod -aG docker you

随机推荐