2023-09-21,   최선빈

본 포스팅은 Docker RemoteAPI 컨테이너 내부 접속에 대한 내용입니다.


 

Docker Exec(Docekr Remote API)

 

  • exec_run()은 Docker Remote API Python SDK에서 컨테이너 내부에 명령어를 전달하는 메소드
  • ‘Docker exec ~’ 명령어와 같음
  • return 값 -> exit_code와 명령어 수행 결과를 담은 객체(Generator, Bytes, Tuple, Socket)
  • 서버에서 exec 명령어(‘docker exec -t test-vol-l ls) 실행 시 클라이언트 코드는 아래와 같음

    _, result = test_container.exec_run(tty=True, cmd='ls')
    print(result.decode('utf-8'))
    
  • 출력 결과

      bin dev hello.py lib media opt root sbin sys tmp var
      boot etc home lib64 mnt proc run srv test usr
    

 

주요 파라미터

 

  • CMD
    • 명령어 입력 (input type: str or list)
  • stdout, stderr, stdin
    • 표준 입출력, 에러 (input type: bool), 기본값(stdout: True, stderr: True, stdin: False)
  • user
    • 명령어를 수행하는 user (input type: str), 기본값 (user=’root’)
  • stream
    • exec_rin() 수행결과 stream (input type bool), 기본값 (stream=False)
    • ‘stream=True’로 설정 시, generator(bytes) 반환
    • ‘stream=Fasle’로 설정 시, bytes 문자열 반환
  • socket
    • 읽기/쓰기가 가능한 SSLSoket 객체 반환 (input type: bool), 기본값 (socket= False)
    • SSLSocket 객체의 send(), recv()를 통해 데이터 읽기/쓰기 가능
  • environmnet
    • 환경 변수 입력 (input type: dict or list)
    • ex. environment=[‘PASSWORD=XXX’, …], environment={‘PASSWORD’:’XXX’,…}
  • workdir
    • 명령어(cmd)를 실행할 경로 설정 (input type: str)
    • ex. workdir=’/home/test/…’
  • tty
    • 수행 결과를 pseudo-TTY로 출력 (input type: bool), 기본값(tty=False)

실행 결과

 

  • ‘ls -l’(bytes 출력)

      _, result = test_container.exec_run(cmd='ls -l',)
      prunt(result.decode('utf-8'))
    
  • 콘솔 출력 결과

      total 4
      drwxr-xr-x.    1  root  root  179  dec  21  2021  bin
      drwxr-xr-x.    2  root  root    6  dec  21  2021  boot
      drwxr-xr-x.    5  root  root  340  Aug  26  14:04  dev
      drwxr-xr-x.    1  root  root   66  Aug  26  14:03  etc
      -rw-rw-r--.    1  root  root  121  Aug  22  15:37  hello.py
      drwxr-xr-x.    2  root  root    6  dec  21  2021  home
      drwxr-xr-x.    1  root  root   41  dec  21  2021  lib
    
  • hello.py는 임의로 컨테이너에 삽입한 파일

  • ‘python hello.py’ (generator 출력)

      _, result = test_container.exec_run(cmd='python hello.py', tty=True, stream=True)
        
      *helllo.py
      while True:
          try:
              print(next(result).decode('utf-8'))
          except StopIteration:
              break
    
  • 콘솔 출력 결과
    • hello.py는 2초 간격으로 날짜가 포함된 문자열을 출력하는 프로그램 (프로그램 종료 시까지)

      2022-08-26 18:17:26.666365 hello world

      2022-08-26 18:17:28.666365 hello world

      2022-08-26 18:17:30.666365 hello world

  • ‘cd /test’

      _, result = test_container.exec_run(cmd='ce /test')
        
      OCI runtime exec failed: exec failed:
      : exec: "cd": executable file not found in $PATH: unknown
    
  • ‘/bin/bash -c ‘cd /test; ls; cp test.txt test-2.txt; ls;’ (bash를 사용한 filesystem 제어)

      _, result = test_container.exec_run(cmd="/bin/bash -c 'cd /test; ls; cp test.txt test-2.txt; ls;'", tty=True, stream=True)
    
  • 콘솔 출력 결과

      test.txt
    
      test-2.txt  test.txt
    
  • 컨테이너 내부 접속 후 확인

      root@c5059143748e:/test$ ls
      test.txt
        
      root@c5059143748e:/test$ ls
      test-2.txt   test.txt
    
  • socket=True로 설정 (SSLSocket 객체 활용)
    • /bin/bash로 시작하는 socket 객체 생성 후 send(), recv()로 통신 시도

      _, socket = test_con.exec_run(cmd'/bin/bash', socket=True, user='root', tty=True, stdin=True)
      
      while True:
        input1 = input(socket recv().decode('utf-8', 'ignore')) + '\n'
        socket.send(input1.encode('utf-8'))
      socket.close()
      
      
      
      root@c5059143748e:/test$ ls
      ls
      ls
      bin  dev  hello.py  lib  media  opt  root  sbin  sys  tmp  var
      boot  etc  home  lib64  mnt  proc  run  srv  test  usr
      ls -l
      ls -l
      root@c5059143748e:/test$ ls -l
      ls
      

 

정리

 

  • exec_run()
    • 단발성 수행
    • 내부 접속 시 흔히 사용하느 bash 기능 사용에 지장
    • 사용하는 명령어가 한정적인 경우 적합 (bash가 필요 없는 경우)
  • exec_run(socket=True)
    • 소켓 연결 종료 시까지 연속적 수행
    • bash로 시작하는 소켓 생성 시, 내부 접속 기능 구현 가능성 있음

업데이트: