【问题标题】:Using Vagrant and Docker to run Python SSH unittests使用 Vagrant 和 Docker 运行 Python SSH 单元测试
【发布时间】:2019-09-16 21:49:33
【问题描述】:

如何配置 Vagrant 以使用 Docker 作为其提供者并使用 Fabric 连接到它?我正在尝试运行一些单元测试,以针对 Ubuntu 18.04 的原始未修改映像验证服务器配置工具。我没有构建自定义图像。

我的 Vagrantfile 是:

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image = "ubuntu:18.04"
    d.remains_running = true
  end
end

我的 Python unittest tests.py 文件看起来像:

import unittest

import vagrant

from fabric.api import settings, run

class Tests(unittest.TestCase):

    def test_connect_to_server(self):

        v = vagrant.Vagrant('.', quiet_stdout=False, quiet_stderr=False)
        v.up(provider='docker')
        with settings(host_string=v.user_hostname_port(), key_filename=v.keyfile(), disable_known_hosts=True):

            run('echo "hello"')

Vagrant 似乎能够创建 Docker 实例,但在 Fabric 连接之前它很快就失败了,并出现错误:

Bringing up machine with provider docker...
Bringing machine 'default' up with 'docker' provider...
==> default: Creating the container...
    default:   Name: ubuntu18_docker_default_1568669393
    default:  Image: ubuntu:18.04
    default: Volume: /path/to/my/project:/vagrant
    default:  
    default: Container created: c5fb82fa523f0774
==> default: Starting container...
==> default: Waiting for container to enter "running" state...
The container started either never left the "stopped" state or
very quickly reverted to the "stopped" state. This is usually
because the container didn't execute a command that kept it running,
and usually indicates a misconfiguration.

If you meant for this container to not remain running, please
set the Docker provider configuration "remains_running" to "false":

  config.vm.provider "docker" do |d|
    d.remains_running = false
  end

所以看起来默认图像正在运行,但它并没有继续运行。如何配置 Docker 以保持映像运行而不是立即退出,以便我可以使用 Fabric 测试 SSH 命令?

编辑:按照 LinPy 的建议,将我的 Vagrantfile 修改为:

我的 Vagrantfile 是:

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image = "ubuntu:18.04"
    d.remains_running = true
    d.cmd = ["tail", "-f", "/dev/null"]
  end
end

修复了最初的错误,但仍然导致测试失败并出现新错误:

Bringing up machine with provider docker...
Bringing machine 'default' up with 'docker' provider...
==> default: Creating the container...
    default:   Name: ubuntu18_docker_default_1568754416
    default:  Image: ubuntu:18.04
    default:    Cmd: tail -f /dev/null
    default: Volume: /path/to/my/project:/vagrant
    default:  
    default: Container created: 0e5023317321c5cf
==> default: Starting container...
==> default: Provisioners will not be run since container doesn't support SSH.
v.user_hostname_port(): vagrant@172.17.0.2:22
v.keyfile(): /home/myuser/.vagrant.d/insecure_private_key
[vagrant@172.17.0.2:22] run: echo "hello"
Keeping VM.
E
======================================================================
ERROR: test_dev_setup_ubuntu18 (__main__.Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/network.py", line 478, in connect
    client.connect(**kwargs)
  File "/path/to/my/project/.env/lib/python3.7/site-packages/paramiko/client.py", line 368, in connect
    raise NoValidConnectionsError(errors)
paramiko.ssh_exception.NoValidConnectionsError: [Errno None] Unable to connect to port 22 on 172.17.0.2

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tests.py", line 167, in test_dev_setup_ubuntu18
    run('echo "hello"')
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/network.py", line 692, in host_prompting_wrapper
    return func(*args, **kwargs)
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/operations.py", line 1095, in run
    shell_escape=shell_escape, capture_buffer_size=capture_buffer_size,
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/operations.py", line 935, in _run_command
    channel=default_channel(), command=wrapped_command, pty=pty,
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/state.py", line 435, in default_channel
    chan = _open_session()
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/state.py", line 416, in _open_session
    transport = connections[env.host_string].get_transport()
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/network.py", line 156, in __getitem__
    self.connect(key)
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/network.py", line 148, in connect
    user, host, port, cache=self, seek_gateway=seek_gateway)
  File "/path/to/my/project/.env/lib/python3.7/site-packages/fabric/network.py", line 610, in connect
    raise NetworkError(msg, e)
fabric.exceptions.NetworkError: Low level socket error connecting to host 172.17.0.2 on port 22: Unable to connect to port 22 on 172.17.0.2 (tried 1 time)

我假设关键信息是“Provisioners will not be run because container doesn't support SSH.”,但我不明白这一点,因为 Ubuntu 18.04 应该预装了 SSHD。我尝试修改 cmd 以安装 SSH,变体如下:

d.cmd = ["apt", "-yq", "install", "openssh-server", "&&", "/etc/init.d/ssh", "start", "&&", "/bin/bash"]

但这没有任何效果,仍然返回相同的错误。为什么 Docker 报告 Ubuntu 容器不支持 SSH?

【问题讨论】:

    标签: python docker vagrant fabric


    【解决方案1】:

    试试这个:

    Vagrant.configure("2") do |config|
      config.vm.provider "docker" do |d|
        d.run "test",
           d.image : "ubuntu:18.04",
           cmd: "tail -f /dev/null",
    
      end
    end
    

    this

    更新

    使用下面的来使用SSH:

    Dockerfile:

    FROM ubuntu
    
    RUN apt-get update && apt-get install -y openssh-server
    RUN mkdir /var/run/sshd
    RUN echo 'root:THEPASSWORDYOUCREATED' | chpasswd
    RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
    
    # SSH login fix. Otherwise user is kicked off after login
    RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
    
    ENV NOTVISIBLE "in users profile"
    RUN echo "export VISIBLE=now" >> /etc/profile
    
    EXPOSE 22
    CMD ["/usr/sbin/sshd", "-D"]
    

    流浪文件:

    Vagrant.configure("2") do |config|
      config.vm.provision "docker" do |d|
         d.build_image "/vagrant/app",
            args: "-t myimage"
      end
    end
    
      Vagrant.configure("2") do |config|
          config.vm.provision "docker" do |d|
           d.run "test",
             d.image : "myimage",
             args: "-p 3333:22"
          end
        end
    

    PS:确保您的Dockerfile/vagrant/app 你的python脚本应该连接到端口3333

    【讨论】:

    • 这似乎是正确的方向。但现在我得到了错误:[Errno None] Unable to connect to port 22 on 172.17.0.2.
    • 是的,因为您使用的映像没有安装 ssh。您需要设置和配置 ssh
    【解决方案2】:

    最近遇到了同样的问题:
    对于以下示例,我将 "nginx_demo" 作为容器名称。

    1. 我们使用 Docker 作为提供者,而不是 VM 作为提供者。
      所以我们不能 ssh 进入容器。

    2. 在容器中运行命令有一些技巧

      $ vagrant docker-run <name> -- <commands>  
      

      例如:这里我使用的是nginx图片,现在让我们获取nginx版本

      $ vagrant docker-run nginx_demo -- nginx -v  
      

      这里 nginx_demo 是将在 Vagrantfile 中给出的名称。 (名字可以是任何东西)

      d.name = "nginx_demo"  
      
    3. 了解 vagrant 支持的其他 docker 命令:

      $ vagrant list-commands  
      
    4. 附加到已经运行的容器

      $ vagrant docker-exec -it nginx_demo -- bash 
      
    5. 获取docker容器的日志

      $ vagrant docker-logs nginx_demo -f  
      

    通过适当的例子了解更多信息
    https://medium.com/@elliot004/vagrant-docker-provider-windows-3350758fc8b3

    【讨论】:

      【解决方案3】:

      如果有人遇到这个问题,我创建了一个 vagrant-docker-communicator:

      https://github.com/ProxiBlue/vagrant-communicator-docker

      它不允许你运行 ```vagrant ssh` 来通过 SSH 连接到盒子,因为很多 docker 镜像实际上并没有 SSH 作为服务运行。 您可以使用其他答案中提到的规定方式使用 docker 通过 bash 提示符连接到正在运行的实例。

      该插件允许在没有 ssh 的 docker 映像上进行配置

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多