원문: A Fog storage software architecture for the Internet of Things

요약(Abstract)

유럽의 Think Tank IDATE Digiworld 은 2030년 350억 장치가 연결될 것으로 예측했다. 이러한 물결은 data, application 및 service 의 폭발적인 성장을 동반할 것이다. 따라서 low latency, mobility (사용자, infrastructure) 및 네트워크 파티셔닝을 지원하는 Fog architecture를 제안하는 것이 매우 시급하다. 이 논문은 확장성과 성능을 모두 허용하는 object store system 과 확장형 NAS (Network Attached Storage) 를 결합하는 아키텍처를 설명한다. 또한 복제 관리를 위한 DNS (Domain Name Service) 에서 영감을 받은 새로운 프로토콜을 제안한다. 마지막으로 Fog Storage, CDN (Content Delivery Networks) 및 NDN (Named Data Networking) 간의 개념에 대해 설명한다. 또한 프랑스 클러스터인 Grid’5000에 대한 실험 평가가 포함된다.

1. Introduction

2012년 시스코에서 제안한 Fog 인프라는 네트워크 edge에 지리적으로 분산된 마이크로 나노 데이터 센터를 배포하는 것으로 구성된다. 각 소규모 데이터 센터는 Fog 사이트로 볼 수 있으며, low latency 기반의 컴퓨팅 및 스토리지 리소스를 제공하는 소수의 서버만 호스팅한다. IoT는 거리 및 전력 관점에서 계층적 토폴로지를 따른다: 클라우드는 네트워크 대기시간 측면에서 가장 긴 대기시간을 가지고 있으면서 가장 큰 컴퓨팅 및 스토리지 기능을 제공한다. Edge 장치는 로컬 컴퓨팅 및 스토리지 리소스의 장점을 가지고 있지만 클라우드에 비해 제한적이다. Fog 사이트는 IT 리소스의 거리와 전력 간의 균형을 제공하는 중간 시설로 볼 수 있다. 또한 Fog 사이트는 사용자 장치와 클라우드 컴퓨팅 센터간 요구를 충족시키기 위해 상호 보완적이다. 프로세싱 및 저장 측면에서 Fog 사이트는 수명이 며칠인 오퍼레이션 데이터를 처리하고 저장하도록 설계되었으며 클라우드 인프라는 몇 달 동안 히스토리를 저장하도록 설계되었다. 즉, 아키텍처는 수직 (클라우드~Edge) 과 수평 (Fog 사이) 을 골고루 갖추고 있다. 이렇게 분산 된 인프라는 대규모 병령 IoT 데이터 스트림을 지원하는데 필요하다. 가장 큰 문제는 어떤 종류의 분산 소프트웨어가 이러한 인프라를 관리하고 무엇을 할 수 있을까?

많은 use cases 가 Fog 인프라의 장점을 누릴 수 있다. 예를들어 Bonomi 등은 connected vehicles 에서 Fog 컴퓨팅을 사용할 것을 제안한다. Fog 는 Thing 으로 부터 메트릭을 수집하고 보행자가 도로에 감지되면 특정 지역의 차량을 정지하는 결정을 내릴 수 있다. 또 다른 use cases 는 Network Function이 사용자의 이동을 따라 움직일 수 있도록 Network Virtualization Functions 을 배포하는 것이다. 이것은 이동 중에 사용자 데이터에 대한 low latency 액세스를 제공하기 위해 버스나 기차에 내장된 Fog 사이트를 이용할 수 있도록 확장되어야 한다. 마지막으로 Fog 컴퓨팅은 인더스트리 4.0에서 사용할 수 있어야 한다. 많은 센서가 데이터를 Fog에 업로드 한 다음 많은 사용자가 이를 처리한다.

그림 1은 이러한 계층 구조와 use cases 일부를 표현하고 있다. 각 사이트는 스토리지 및 컴퓨팅을 제공하는 제한된 서버를 호스팅한다. 최종 사용자 장치 (스마트폰, 테블릿, 랩톱 등) 와 IoT 장치 (센서, 스마트 빌딩 등) 는 10ms (무선 링크 latency) 보다 짧은 low latency (LFog) 로 Fog 사이트에 도달할 수 있다. Fog 사이트 (LCore) 간의 latency 시간은 50ms (Wide Area Network link 의 평균 latency) 이다. 클라이언트에서 클라우드 플랫폼 (LCloud) 에 도달하는 latency 시간은 더 높으며 (약 200ms) 예측할 수 없다. 이 논문에서는 데이터 저장이 처리의 전제 조건이라고 주장한다. 따라서 엄청난 수의 IoT 장치에서 생성되는 방대한 양의 데이터를 처리하려면 Fog 계층에 배포 된 효율적인 스토리지 솔루션이 필요하다. 그러나 다중 사이트 및 low latency 에서 동작하도록 설계된 단일 스토리지 솔루션은 현재 존재하지 않으며 이것이 목표이다.

+----------------+                           [Cloud Computing]
|Domestic Network|-----------+                        |                                         +-----------+
+--------+-------+           |                 Cloud Latency                              +-----|Edge Device|
         |               +--------+                = 200ms                 +--------+     |     +-----------+
         |               |Fog site|----------+        |         +----------|Fog site|-----+-----|Edge Device|
         |               +--------+          |        |         |          +--------+     |     +-----------+
+--------+---------+         |               |        |         |                         +-----|Edge Device|
|Enterprise Network|---------+               |        |         |                               +-----------+
+------------------+                      +-----------------------+                    Edge to Fog latency
                                          |Inter Micro DCs latency|                         [10-100ms]
+-----------+                             |     [50ms~100ms]      |
|Edge Device|----------------+            +-----------------------+
+-----------+                |               |                  |
                         +--------+          |                  |          +--------+
                         |Mobile  |----------+                  +----------|Micro   |
                         |Fog site|                                        | Nano DC|
                         +--------+                                        +--------+
+-----------+                |              Site of Fog Computing
|Edge Device|----------------+
+-----------+

<Extreme Edge Frontier> | <Edge Frontier>                             <Edge Frontier>

이 논문의 목표를 위해 첫번째로 이러한 네트워크에서 데이터를 찾기위한 기존 전략의 장점과 단점을 제시한다. 둘째로 로컬에 저장된 데이터를 보다 효율적으로 찾을 수 있는 로컬 Scale-Out NAS 를 추가하여 기존의 스토리지 솔루션을 개션한다. 마지막으로 분산 네트워크에서 데이터를 효율적으로 찾을 수 있는 새로운 프로토콜을 제안한다. 특히 데이터 (미디어) 가 네트워크 edge 에서 생성되고 다른 사이트와 공유되는 Content Delivery Network 의 시나리오에 중점을 둔다. 이러한 use cases 의 주요 관점은 데이터가 수정되지 않기 때문에 복제는 static replicas 라는 것이다. 이 특성은 consistency 을 고려하지 않을 수 있다는 것이다.

다음 장에서 Fog 인프라에 이상적인 스토리지 솔루션이 무엇인지 알아보고 클라우드 아키텍처 용으로 개발된 기존 솔루션을 사용할 수 없는 이유를 알아보고 개선하기 위한 솔루션을 제시한다.

2. Distributed storage for the Fog: an overview

Fog 인프라 기반으로 설계된 이상적인 스토리지 솔루션에서 기대하는 속성을 소개한다.

2.1. Properties for an object store working in a Fog environment

  • 목표: 대량의 데이터와 많은 액세스를 병렬로 처리할 수 있는 Fog 스토리지
    • 각 사용자와 IoT 장치는 모든 오브젝트에 효율적으로 액세스할 수 있어야 함

이상적인 스토리지가 충족할 5가지 속성은 다음과 같다.

  • Data locality:
    • 액세스 시간을 줄이기 위해 사용자와 가장 가까운 사이트에 데이터를 작성(low latency)해야 함
    • 읽기 데이터는 리모트 액세스가 금지된 사이트에 있어야 함
    • 높은 서비스 품질외에도 예상할 수 있는 결과는 개인 정보 보호 및 지속성
  • Data availability:
    • 스토리지 노드는 신뢰할 수 없는 링크로 연결되며 수 많은 사이트에 분산
    • 이상적인 스토리지는 내결함성 (fault tolerant) 이 있어야 함
    • 격리 오류 (isolated failures) 는 발생하는 사이트 내에서 관리해야 하며 연결할 수 없는 (unreachable site) 사이트는 다른 사이트에 영향을 주지 않아야 함
      • 예) 버스나 기차에 포함된 모바일 Fog 사이트
  • Network containment:
    • 네트워크 억제 (network containment) 는 네트워크 트래픽을 제한하는 것으로 구성
    • 이 속성은 다음과 같은 세가지 측면이 있음
      • 첫째: 사용자 액션만 사이트간에 교환되는 네트워크 트래픽을 생성하여야 함
      • 둘째: 사이트에 대한 액세스가 다른 사이트의 성능에 영향을 주지 않아야 함, 사이트가 다른 사이트보다 더 많이 요청될 때 다른 사이트는 성능 저하가 없어야 함
      • 셋째: 사용자가 연결된 사이트에 저장되지 않은 데이터에 액세스하기 전에 데이터를 찾아야 함, 그럼에도 불구하고 참여하지 않는 사이트는 연결하지 않아야 함
    • 이러한 맥락에서, 물리 토폴로지를 고려하여야 함
    • low latency 링크를 통해 연결된 가까운 사이트간 교환이 선호되어야 함
      • 예) 직장과 집 사이에 문서를 공유하는 경우 이 두 위치 사이의 도로에 있는 Fog 사이트만 요청하여야 함
  • Disconnected mode:
    • 네트워크 장애로 인해 다른 사이트에 접속할 수 없을 때 사이트에 로컬로 저장된 데이터에 액세스하는 기능은 필수 속성
    • 사이트는 가능한 독립적 구성이 되어야 함
      • 예) 모바일 Fog 사이트에 연결된 사용자는 네트워크 파티셔닝의 경우에도 데이터 액세스가 가능하여야 함
  • Mobility support:
    • 사용자는 이동성을 지니고 있으며 항상 low latency 시간으로 연결할 수 있는 사이트에 연결됨
    • 요청된 데이터가 로컬 사이트에 저장되지 않은 경우 데이터를 다운로드하며 현재 사이트에 캐시하여 향후 액세스 성능을 향상시키고 예측 가능한 액세스를 수행함
  • Scalability:
    • Fog 아키텍처를 위한 이상적인 스토리지는 많은 사이트와 클라이언트로 확장가능 하여야 함

결론적으로, 이러한 특성은 Brewer 정리를 염두에 두고 이해할 수 있다. Brewer 정리는 일관성, 데이터 가용성 (예: 클라이언트가 제한 시간내에 응답을 받음) 및 네트워크 파티셔닝을 동시에 지원할 수 없음을 알수있다. 데이터 가용성 (availability) 및 disconnected mode 는 이상적 스토리지를 위해 원하는 속성 목록이 있기 때문에 일관성 (consistency) 은 네트워크 파티셔닝의 경우 항상 충족할 수 있는 속성이 아니다. 이러한 이유로 모든 데이터를 불변 (immutable) 으로 간주하고 모든 복제본을 정적 (static) 으로 간주한다. 즉, 액세스 패턴은 write-only, read-many 이다.

2.2. From Cloud storage solutions to Fog: the metadata management challenge

Fog 노드는 지리적으로 분산되어 있기 때문에 스토리지는 이러한 환경에서 동작하기 위하여 가장 중요한 것은 데이터를 찾는 것이다.

전통적인 분산 파일 시스템은 중앙 집중식 메타데이터 서버에 의존한다. 아래 그림과 같이 클라이언트는 먼저 메타데이터 서버에 연결하여 데이터를 찾은 다음 복제본을 저장하는 노드에 전달한다. 이 접근 방식은 PVFS, Luster 와 같은 HPC (High Performance Computing) 또는 RozoFS 와 같은 IO 집약적 Scale-Out NAS 에 사용된다.

########## [sequence diagram showing how a client can access a data in a traditional distributed storage solution] ##########

+------+        +---------------+ +---------------+ +---------------+ +---------------+
|client|        |metadata server| |storage server1| |storage server2| |storage server3|
+------+        +---------------+ +---------------+ +---------------+ +---------------+
   |                    |                 |                  |                 |
   |     where is       |                 |                  |                 |
   | {data identifier}? |                 |                  |                 |
   |------------------->|                 |                  |                 |
   |    on "server2"    |                 |                  |                 |
   |<-------------------|                 |                  |                 |
   |                    |                 |                  |                 |
   |                   read {data identifier}                |                 |
   |-------------------------------------------------------->|                 |
   |                     data = "mydata"                     |                 |
   |<--------------------------------------------------------|                 |

그럼에도 불구하고 이러한 접근은 많은 수의 스토리지 노드와 엄청난 워크로드를 동반하는 대규모 배포에 필요한 확장성을 제공할 수 없으며 중앙 집중식 메타데이터 서버가 로컬 사리트에 없는 분산 환경에서 동작할 수 없다. 이러한 문제를 극복하기 위해 오브젝트 스토리지는 각 데이터가 단순히 이름과 연결되는 플랫 네임스페이스 (flat namespace) 가 필요하다. 이렇게 하면 디렉토리가 없기 때문에 저장하고 액세스할 메타데이터의 양이 줄어든다. 결과적으로 중앙 집중식 메타데이터 서버는 요청이 적고 확장성이 좋지만 DHT 와 같은 성능이 떨어지는 메커니즘으로 대체된다.

2.2.1. Approaches to locate data in a distributed manner

모든 스토리지의 주요 기능인 분산 방식으로 데이터를 찾는 접근 방법을 제시한다. Fog 스토리지에 대한 2.1 섹션의 5가지 속성을 위치 프로세스 (location process) 를 기반한 5개의 속성을 제안한다.

  • (i) Access time 은 위치 기록이 사용자와 얼마나 가까운지 평가함. 위치 기록에 대한 “data locality” 속성의 확장임
  • (ii) 사이트를 추가하거나 제거하는 동안 발생하는 네트워크 트래픽
  • (iii) 네트워크 토폴로지에 대한 지식 은 위치 접근 방식이 확장 가능하고 사이트 자체의 이동성에 대한 반응을 평가함
  • (iv) 오프젝트를 찾기위한 네트워크 트래픽 양 은 위의 “network containment” 속성과 연관이 있음
  • (v) 최소 중복성 (minimal redundancy) 은 속성 ““에 해당함. 모든 노드에서 위치 정보를 복제해야 하는 접근 방식은 확장에 문제가 있음

데이터를 찾는데 일반적으로 사용되는 6가지 소프트웨어 솔루션을 다음과 같이 평가하였다: 중앙 집중식 메타데이터 서버, flooding, gossip, hash function, DHT, one-hop DHT. 아래 그림은 다이어그램에서 이런 분석을 보여준다.

Centralised metadata server: 중앙 집중식 메타데이터 서버는 확장되지 않으며 오브젝트를 찾기위해 원격 사이트를 사용하는 것은 액세스 시간에 큰 영향을 미친다. 이 접근 방식의 장점은 모든 노드가 전체 네트워크 토콜로지가 아닌 오브젝트를 찾을 수 있는 메타데이터 서버의 주소만 알면 된다는 것이다. 중앙 집중식 메타데이터 서버가 영향을 받지 않는한 네트워크 토폴로지 변경을 지원한다.

Flooding: 이 방식은 오브젝트 위치를 저장할 필요가 없다. 각 노드는 오브젝트의 요청이 오브젝트를 저장하는 노드에 도달할 때까지 이웃에 전달한다. 루프를 방지하기 위해 요청은 TTL (Time-To-Live) 에 연결된다. 이 접근법의 장점은 모든 노드가 네트워크 토폴로지를 알 필요가 없다는 것이다. 또한 네트워크 토폴로지를 모르기 때문에 교란 (churn) 을 지원한다. 그러나 이 접근법의 단점은 요청된 오브젝트에 도달하는데 시간을 예상할 수 없으며 생성된 네트워크 트래픽의 엄청난 오버헤드가 있다는 것이다. 많은 노드들이 저장하지 않은 오브젝트에 대한 요청을 받는다. 또한 기존 오브젝트를 찾은데 성공할 것이라는 보장도 없다.

Gossip: 이 방식은 각 노드가 임의의 이웃을 선택하고 오브젝트 위치에 대한 모든 정보를 전송하는 방식이다. 이 작업을 정기적으로 반복하여 각 노드는 모든 오브젝트의 위치를 파악한다. 결과적으로 모든 노드는 모든 오브젝트의 위치를 저장한다. 즉, 위치 정보가 네트워크를 통해 전파된다. 위치가 모든 노드로 전파되면 네트워크에서 아무런 연결없이 모든 오브젝트를 찾을 수 있다. 또한 노드가 전체 네트워크 토폴로지를 알 필요가 없으며 인접 항목만 알고 있으면 된다. 이러한 제한된 지식으로 인하여 많은 새로운 정보를 전파하지 않고 이탈 (chrun) 관리를 수행할 수 있다. 그럼에도 불구하고 가장 큰 단점은 각 오브젝트의 위치가 모든 노드에 저장되어 스토리지 비용이 증가한다는 것이다. 또한 추가 교환없이 데이터를 찾을 수 있도록 하기전에 모든 노드에 있는 모든 데이터의 위치 기록을 전파하기 위해 엄청난 네트워크 트래픽을 고려해야 한다. 실제로 필요할 때 네트워크 트래픽을 생성하지 않고 미리 생성한다. 이것이 백그라운드 트래픽을 데이터를 찾는데 필요한 네트워크 트래픽으로 고려하여야 하는 이유이다.

Hash function: 오브젝트 이름에 해시 함수를 적용하는 것은 또 다른 방법이다. 이를 통하여 네트워크에 요청하지 않고 모든 오브젝트를 찾을 수 있다. 이 방법의 장점은 네트워크 교환없이 매우 빠르게 위치를 찾을 수 있다는 것이다. 그러나 단점은 특정 데이터를 저장할 위치를 명시적으로 선택하지 않는 것이다. 또한 각 노드는 해시 함수로 계산된 값에서 노드 주소를 연관시킬 수 있도록 네트워크의 전체 토폴로지를 알아야 한다. 또한 네트워크 토폴로지가 변경될 때 해시 값고 노드간의 기존 매핑을 사용할 수 없게 된다. 따라서 네트워크에서 노드가 이탈 (churn) 된 경우 오브젝트를 이동해야 한다. 일관성있는 해싱은 이탈시 이동할 오브젝트 수를 최소화한다.

Distributed Hash Table: DHT 는 오브젝트를 찾기위해 생성된 네트워크 트래픽의 양과 각 노드의 토폴로지 지식 사이의 균형을 제공한다. 각 키 (key) 는 키에서 계산된 해시 값 바로 뒤에 있는 식별자와 함께 노드에 저장된다. 라우팅 테이블은 각 노드가 로그 갯수의 이웃을 알고 로그 갯수의 홉으로 모든 키에 도달할 수 있도록 계산된다. 이 방법의 장점은 오브젝트를 찾는데 필요한 네트워크 교환과 각 노드가 가지고 있는 토폴로지 지식의 양 사이에 적절한 균형을 유지한다는 것이다. 또한 DHT 는 최소한의 오브젝트를 이동하여 이탈을 가능하게 한다. 그러나 단점은 사용자가 데이터를 저장할 위치를 선택할 수 없다는 것이다.

One-Hop Distributed Hash Table: hash function 과 gossip 방식의 혼합이다. gossip 프로토콜을 사용하여 각 오브젝트의 위치를 보내는 대신 네트워크 토폴로지를 모든 노드로 전파한다. 각 노드는 자신이 담당하는 키 범위의 이웃에게 보내고 네트워크의 모든 노드에 대헤 이러한 값을 포함하는 테이블을 작성한다. 그런 다음 오브젝트를 찾기 위해 이름의 해시를 계산한 다음 해시 값을 포함하는 키 범위를 담당하는 노드에 전달된다. 네트워크 토폴로지가 모든 노드에 gossip 을 사용하면 위치 프로세스는 hash function 의 장점과 비슷하다. 그러나 단점은 위치가 모든 노드에 복제되어 저장공간 사용 측면에 비용이 많이 발생한다는 것이다.

위치 기록을 저장하는 가장 좋은 방법은 액세스 시간에 영향을 주지 않으며, 오브젝트가 위치할 때 및 네트워크에서 사이트가 추가 또는 제거될 때 네트워크 트래픽을 교환하는 방식이다. 따라서 각 노드가 각 오브젝트 위치를 저장하고 전체 토폴로지를 알 필요가 없는 것이 가장 좋은 방법이다.

2.2.2. Existing Cloud storage solutions

이 섹션은 기존 클라우드 인프라의 오브젝트 저장소를 제시하고 Fog 환경에 적용 평가를 제안한다.

특히 데이터를 찾기 위해 이전 섹션 (섹션 2.2.1) 에서 제시한 메커니즘에 의존하는 Rados, Cassandra, IPFS 에 중점을 둔다.

Rados: Rados 는 CRUSH 라는 hashing function 을 사용하여 데이터를 찾는다. 선출된 노드는 네트워크 토폴로지를 설명하는 맵과 모든 스토리지 노드 및 클라이언트에 대한 배치 제한 사항을 배포하는 역할을 한다. 이후 각 노드는 네트워크 교환없이 각 오브젝트의 위치를 로컬로 계산할 수 있다. Rados 주요 장점은 hash function 으로 네트워크 트래픽을 포함하지만 Paxos 프로토콜을 사용하여 모든 노드에 네트워크 토폴로지 설명을 배포하기 때문에 네트워크 파티셔닝이 동작하지 않는다. 또한 기존에 저장된 데이터를 이동하는 것이 쉽지 않기 때문에 이동성에 대한 지원이 제한된다.

Cassandra: Facebook 에서 개발한 것으로 gossip 과 hash function 을 활용하는 ‘one-hop DHT’ 를 사용한다. Cassandra 에서 각 노드는 네트워크 토폴로지에 대한 지식을 보내기 위해 무작위로 선택된 다른 노드에 주기적으로 연결한다. 이후 Rados 와 같이 다른 요청없이 각 노드에서 오브젝트를 찾을 수 있다. Rados 와 차이점은 토폴로지를 설명하는 맵이 노드에 분산되는 방식이다. Cassandra 의 장단점은 Rados 와 동일하지만 토폴로지 설명을 배포하기 위해 Paxos 프로토콜을 사용하지 않으므로 Brewer 정리에 따라 네트워크 파티셔닝을 사용할 수 있다.

IPFS: BitTorrent 프로토콜을 사용하여 노드간 데이터를 교환하고 Kademlia DHT 를 통해 오브젝트 복제본을 저장하는 노드를 찾는 오브젝트 저장소이다. 장점은 각 노드가 네트워크 토폴로지에 대한 제한된 지식을 가지고 있기 때문에 요청된 노드에 복제본은 생성하는 것으로 네트워크 파티셔닝을 지원한다. 그러나 단점은 불변 (immutable) 오브젝트를 사용하는 것이다. 이것은 오브젝트는 수정될 수 없음을 의미하며 DHT 가 네트워크 트래을 포함하지 않는다.

아래 표에 위 내용을 요약하였다. 대부분 엄청난 숫자의 서버를 대상으로 높은 대기시간과 이기종 네트워크 링크로 연결된 다중 사이트 환경에서 작동하는 것을 염두하지 않고 설계되었다. 일부 분산 파일시스템인 XtreemFS, GFarm, GlobalFS 등과 같은 WAN 링크와 상호 연결된 다중 사이트 환경을 지원하는 것이 있지만 오브젝트 스토리지가 아닌 파일 시스템인 관계로 중앙 집중식 접근 방식에 의존하기 때문에 Fog 에서 기대하는 성능을 나타내지 않는다.

########## summary of the advantages and disadvantages of the presented storage solutions ##########

  제안 (Purpose) 장점 (Advantages) 단점 (Disadvantage)
Rados - CRUSH hash function 과 Paxos 프로토콜에 의존하는 오브젝트 스토리지 - 네트워크 교환 없이 데이터 탐색 (CRUSH) - (Paxos 프로토콜) 네트워크 파티셔닝이 동작하지 않음
- 확장이 어려움 (Paxos 프로토콜)</br>
- 저장된 데이터 이동의 어려움</br>
Cassandra - hash function 및 gossip 프로토콜에 의존하는 Key/Value store - 네트워크 교환없이 데이터 배치
- (gossip) 네트워크 파티셔닝 가능</br>
- 저장된 데이터 이동이 어려움
IPFS - BitTorrent 프로토콜 및 DHT 에 의존하는 P2P 오브젝트 저장소 - 데이터를 새 위치로 자동 재배치: 액세스 시간 개션
- 네트워크 파티셔닝 가능</br>
- DHT 는 네트워크 트래픽을 포함하지 않음
- immutable 오브젝트 활용</br>

2.3. How existing solutions fit the properties

스토리지 솔루션을 처음부터 개발하지 않기 위해 Fog 인프라를 도입 (Rados, Cassandra, IPFS) 한 오브젝트 저장소를 배포하고 성능과 Fog 스토리지에 대한 평가를 진행하였다. 아래 표를 보면 기존 해결책이 Fog 스토리지의 속성을 충족하지 않는다는 것을 알 수 있다. Rados 는 Paxos 알고리즘을 사용하면 서비스 파티셔닝의 경우 데이터를 사용할 수 없게되고 Cassandra 의 경우 사용자가 이동하는 사이트에 저장된 오브젝트를 이동하여 액세스 시간을 늘리는 유연성이 부족하다. IPFS 는 배치 전략이 없기 때문에 기본 이동성만 제공한다. 클라이언트는 원하는 위치에 쓰고 오브젝트 저장소는 각 데이터 오브젝트가 기록된 위치를 추적한다.

########## summary of Fog characteristics a priori met for 3 different object stores ##########

  Rados Cassandra IPFS
Data locality Yes Yes Yes
Network containment Yes Yes No
Disconnected mode No Yes Partially
Mobility support Partially Partially Natively
Scalability No Yes Yes

결과적으로 IPFS 오브젝트 저장소를 활용할 것을 제안하고 모든 속성이 충족될 수 있도록 Fog 환경에서 동작을 위한 수정사항을 제안한다. 이동성 지원은 스토리지 핵심에서 배치 전략을 수정하지 않고 추가할 수 없는 필수 속성이기 때문에 IPFS 로 시작하기로 결정하였다.

3. Designing a scalable and efficient Fog Layer

Fog 에서 사이트간 네트워크 교환은 비용이 많이 소요된다. 액세스 시간을 줄이는 것뿐만 아니라 (네트워크 파티셔닝으로 인한 무한 지연이 발생한 극단적인 경우) 네트워크 지연이 큰 환경에서 시스템이 동작할 수 있도록 하여야 한다.

다음 섹션에서 IPFS 오브젝트 스토리지를 Fog 환경에 적용하는 것을 중점적으로 살펴본다. 섹션 3.1 에 제시한 첫번째 수정은 사용자가 로컬로 저장된 오브젝트에 접근하는 동안 네트워크를 억제하는 것이다. 이를 위해 IPFS 를 Scale-out NAS 와 결합할 것을 제안한다.

두번째 수정은 데이터 저장 프로세스에서 네트워크 트래픽을 포함하도록 물리적 네트워크 토폴로지를 매핑하는 트리에 오브젝트의 위치를 저장하는 것으로 구성된다. 이것은 섹션 3.2 에서 다룬다.

3.1. Reduction of inter-sites network traffic for locally stored data

IPFS 가 오브젝트를 찾기 위하여 사용하는 DHT 가 네트워크 트래픽을 포함할 수 없는 이유를 설명한다. 둘째로 사용자가 사이트간 네트워크 요청을 보내지 않고도 연결된 사이트에 로컬로 저장된 오브젝트에 액세스할 수 있도록 IPFS 를 Scale-Out NAS 와 결합하는 방식을 설명한다.

3.1.1. Problem description

DHT 제한을 이해하기 위해 IPFS 에서 관찰한 네트워크 교환을 설명한다.

신규 오브젝트 생성: 클라이언트는 가장 가까운 사이트에 있는 모든 노드 (네트워크 대기 시간 측면) 로 오브젝트를 보냄. 오브젝트는 로컬에 저장되고 각 오브젝트 위치를 저장하는 DHT 가 업데이트 됨. DHT 는 지역성을 제공하지 않기 때문에 오브젝트 위치를 네트워크의 모든 노드에 저장할 수 있다. 아래 그림에서 site2 에 있는 노드3은 site1 에 기록된 오브젝트의 위치를 저장한다. 이 노드는 오브젝트 식별자에 대한 hash function 으로 결정됨.

########## [writing of an object] ##########

[############### <site1> ###############]      [## <site2> ##] 

+------+  +----------+       +----------+       +----------+
|client|  |IPFS node1|       |IPFS node2|       |IPFS node3|
+------+  +----------+       +----------+       +----------+
   |            |                                     |
   |    put     |                                     |
 {object idenrifuer}=                                 |
   |   "data"   |                                     |
   |----------->|                                     |
   |            |---+                                 |
   |            |   |                                 |
   |           store objceet                          |
   |            |   |                                 |
   |            |<--+                                 |
   |            |                                     |
   |            |        add locatino in DHT:         |
   |            | "{object identifier} in IPFS node1" |
   |            |------------------------------------>|

클라리언트가 로컬에 저장된 오브젝트를 읽을때: 노드가 특정 오브젝트에 대한 요청을 수신할 때 마다 오브젝트가 하드 드라이브에 저장되지 않았는지 확인함. 그렇지 않은 경우 i) 오브젝트 이름에 따라 해시 계산, ii) 위치를 저장하는 노드 연결, iii) BitTorrent 와 같은 프로토콜을 통해 오브젝트 다운로드, iv) 로컬 오브젝트가 클라이언트로 전달되는 동안 복제본 생성, v) DHT 가 새 복제본의 존재를 반영하도록 업데이트

########## [reading of an object stored on the local site] ##########

[############### <site1> ###############]      [## <site2> ##]

+------+  +----------+       +----------+       +----------+
|client|  |IPFS node1|       |IPFS node2|       |IPFS node3|
+------+  +----------+       +----------+       +----------+
   |            |                 |                   |
get: {object identifire}          |                   |
   |----------->|                 |                   |
   |            |---+             |                   |
   |            |   |             |                   |
   |           read object        |                   |
   |            |   |             |                   |
   |            |<--+             |                   |
    object="data"                 |                   |
   |<-----------|                 |                   |
   |            |                 |                   |
   |   get {object identifier}    |                   |
   |----------------------------->|     DHT:local     |
   |            |                 |{object identifier}|
   |            |                 |------------------>|
   |            |                 |   in IPFS node1   |
   |            |                 |<------------------|
   |            |     get/read    |                   |
   |            {object identifier}                   |
   |            |<----------------|                   |
   |            |  object="data"  |                   |
   |            |---------------->|                   |
   |            |                 |                   |
   |         object="data"        |                   |
   |<-----------------------------|                   |
   |            |                 |---+               |
   |            |                 |   |               |
   |            |                store object         |
   |            |                 |   |               |
   |            |                 |<--+               |
   |            |                 |                   |
   |            |              DHT: add '{object identifier}
   |            |                 |   in IPFS node2'  |
   |            |                 |------------------>|

원격 사이트에서 오브젝트를 요청할 때 프로토콜: 클라이언트가 한 사이트에서 다른 사이트로 이동하는 경우에 사용된다. 우리는 모든 상황에서 클라이언트가 가장 가까운 사이트에 있는 노드 (네트워크 대기 시간 측면) 에 접속한다는 것을 정확하게 알고 있음. 즉, IPFS 더 구체적으로 사용하는 DHT 는 Fog 의 물리적 토폴로지를 고려하지 않음. 각 서버는 동일 사이트에 있는 컴퓨터 클러스터의 일부가 아니라 독립적인 것으로 간주됨 (아래 그림의 첫번째). 사용자 또는 재배치 프로세스에 의해 새 오브젝트 복제본이 만들어지면 사이트의 다른 IPFS 노드는 새 복제본의 존재를 알리지 않고 DHT 를 사용하여 찾음 (아래 그림의 두번째). 오브젝트가 site3 의 노드4 에서 이미 사용 가능하지만 노드5 는 DHT 에 연결하여 위치를 찾아야 함.

이것을 볼 때 여기는 두가지 단점이 있다. 첫째, 이런 프로세스는 사이트간 액세스 시간과 네트워크 트래픽을 증가시킨다. 둘째, 클라이언트는 오브젝트의 위치를 찾을 수 없기 때문에 사이트가 다른 사이트와 연결이 끊어지면 (네트워크 파티셔닝) 사이트에 저장된 모든 오브젝트에 액세스 할 수 없다. IPFS 는 BitTorrent 프로토콜을 사용하여 데이터에 액세스하는 방법을 제공하지만 Fog 컴퓨팅의 특수성을 고려하지 않는다.

########## [reading of an object stored on a remote site (by requesting a local node: IPFS node4 or IPFS node5)] ##########

[####### <site1> #######]  [## <site2> ##]   [########### <site3> ###########]

+----------++----------+     +----------+     +----------++----------++------+
|IPFS node1||IPFS node2|     |IPFS node3|     |IPFS node4||IPFS node5||client|
+----------++----------+     +----------+     +----------++----------++------+
      |           |                |                |           |         |
      |           |                |                get {object identifier}
      |           |                |   DHT: local   |<--------------------|
      |           |                {object identifier}          |         |
      |           |                |<---------------|           |         |
      |           |                in IPFS node1 & 2            |         |
      |           |                |--------------->|           |         |
      |     get/read {object identifier}            |           |         |
      |<--------------------------------------------|           |         |
      |              object="data"                  |           |         |
      |-------------------------------------------->|           |         |
      |           |  get/read {object identifier}   |           |         |
      |           |<--------------------------------|           |         |
      |           |          object="data"          |           |         |
      |           |-------------------------------->|    object="data"    |
      |           |                |                |-------------------->|
      |           |                |                |           |         |
      |           |                |                |---+       |         |
      |           |                |                |   |       |         |
      |           |                |               store object |         |
      |           |                |   DHT: add     |   |       |         |
      |           |            "{object identifier} |<--+       |         |
      |           |                  in IPFS node4" |           |         |
      |           |                |<---------------|           |         |



[####### <site1> #######]  [## <site2> ##]   [########### <site3> ###########]

+----------++----------+     +----------+     +----------++----------++------+
|IPFS node1||IPFS node2|     |IPFS node3|     |IPFS node4||IPFS node5||client|
+----------++----------+     +----------+     +----------++----------++------+
      |           |                |                |           |         |
      |           |                |                |    get {object identifier}
      |           |                |                |           |<--------|
      |           |               DHT: locate {object identifier}         |
      |           |                |<---------------------------|         |
      |           |                |    in IPFS node1, 2 & 4    |         |
      |           |                |--------------------------->|         |
      |           get/read {object identifier}                  |         |
      |<--------------------------------------------------------|         |
      |                     object="data"                       |         |
      |-------------------------------------------------------->|         |
      |           |        get/read {object identifier}         |         |
      |           |<--------------------------------------------|         |
      |           |                object="data"                |         |
      |           |-------------------------------------------->|         |
      |           |                 |       get/read {object identifier}  |
      |           |                 |                |<---------|         |
      |           |                 |               object="data"         |
      |           |                 |                |--------->|         |
      |           |                 |                |         object="data"
      |           |                 |                |          |-------->|
      |           |                 |                |          |---+     |
      |           |                 |                |          |   |     |
      |           |                 |         DHT: add       store object |
      |           |                 |   "{object identifier}    |   |     |
      |           |                 |       in IPFS node5       |<--+     |
      |           |                 |<--------------------------|         |

3.1.2. A Fog storage software architecture

Fog 컴퓨팅 환경에서 IPFS 를 적용하기 위해 Scale-Out NAS 와 같은 각 사이트에 독립적으로 분산 파일 시스템을 배포할 것을 제안한다. 이러한 Scale-Out NAS 는 아래 그림과 같이 사이트의 모든 IPFS 노드에 대한 기본 스토리지 솔루션으로 사용된다. 이 접근법을 사용하면 IPFS 노드가 사이트의 다른 노드에서 저장한 모든 오브젝트에 액세스할 수 있으며 소스 코드를 거의 수정하지 않아도 된다. 이러한 결합은 각 IPFS 노드가 각 오브젝트를 파일에 내부적으로 저장하기 때문에 가능하다. 로컬 파일 시스템의 파일에 액세스하는 대신 IPFS 는 Scale-Out NAS 에서 제공하는 분산 파일 시스템에 액세스한다.

########## [The Fog software architecture combining an object store (IPFS) and a Scale-Out NAS (like RozoFS)] ##########

           +--[site1]-----------------------------------+
           |                                            |
           | +--------[scale-out NAS]-----------------+ |
           | |               metadata                 | |
           | |+--------++--------++--------++--------+| |
           | ||storage1||storage2||storage3||storage4|| |
           | |+--------++--------++--------++--------+| |
           | |                                        | |
           | +--------[object store]------------------+ |
           | |+--------++--------++--------++--------+| |
           | || node1  || node2  || node3  || node4  || |
           | |+--------++--------++--------++--------+| |
           | +----------------------------------------+ |
           |                   client                   |
           +--------------------------------------------+
                                 |
                                 |
     +---------------------------+----------------------------+
     |                                                        |
+--[site2]-----------------------------------+           +--[site3]-----------------------------------+
|                                            |           |                                            |
| +--------[scale-out NAS]-----------------+ |           | +--------[scale-out NAS]-----------------+ |
| |               metadata                 | |           | |               metadata                 | |
| |+--------++--------++--------++--------+| |           | |+--------++--------++--------++--------+| |
| ||storage1||storage2||storage3||storage4|| |           | ||storage1||storage2||storage3||storage4|| |
| |+--------++--------++--------++--------+| |           | |+--------++--------++--------++--------+| |
| |                                        | |           | |                                        | |
| +--------[object store]------------------+ |           | +--------[object store]------------------+ |
| |+--------++--------++--------++--------+| |           | |+--------++--------++--------++--------+| |
| || node1  || node2  || node3  || node4  || |           | || node1  || node2  || node3  || node4  || |
| |+--------++--------++--------++--------+| |           | |+--------++--------++--------++--------+| |
| +----------------------------------------+ |           | +----------------------------------------+ |
|                   client                   |           |                   client                   |
+--------------------------------------------+           +--------------------------------------------+

오브젝트 저장소를 Scale-Out NAS 와 결합하는 것은 새로운 아이디어가 아니며 이미 많은 제안이 되어있다. 예를들어 Yahoo 는 HDFS (Hadoop Filesystem) 와 같은 다양한 파일 시스템에 의존하는 오브젝트 저장소인 Wlanut 을 개발했다. 그러나 기본 Scale-Out NAS 가 전역 파일 시스템이 아니라 각 사이트에 로컬인 분산 파일 시스템이기 때문에 제안하는 접근 방법이 다르다. IPFS 는 다른 사이트를 통해 전역 네임 스페이스를 만드는 접착체일 뿐이다. 비슷한 접근 방식이 GBFS (Group Base FileSystem) 에서 이미 제안되었다. 여기서 서로 다른 위치에 배포된 서로 다른 파일 시스템이 공통 네임스페이스로 집계된다. 이것은 모든 액세스가 루트 디렉토리를 담당하는 서버를 요청하는 엄청난 워크로드를 발생시키기 때문에 효율적이지 않다. 접근 방식의 차이점은 오브젝트 저장소에 의존하기 때문에 병목 현상이 될 루트 디렉토리가 없다는 것이다.

RozoFS 또는 GlusterFS 와 같은 Scale-Out NAS 사용의 관심은 노드를 즉석에서 추가할 수 있는 기능으로, 요청이 서로 다른 노드간 균일하게 분산되기 때문에 스토리지 공간뿐만 아니라 시스템 성능도 향상된다.

오브젝트를 노드에 직접 저장하는 대신 분산 파일 시스템으로 보낸다.

########## [writing] ##########

[###################### <site1> #######################]   [<site2>]

+------+ +-------+ +-------+ +------+ +------+ +-------+   +-------+
|client| |IPFS n1| |IPFS n2| |DFS n1| |DFS n2| |DFS MDS|   |IPFS n3|
+------+ +-------+ +-------+ +------+ +------+ +-------+   +-------+
   |         |         |         |        |        |           |
   |   put   |         |         |        |        |           |
{object identifier}=   |         |        |        |           |
   | "data"  |         |         |        |        |           |
   |-------->| get DFS Nodes to store {object identifier}      |
   |         |------------------------------------>|           |
   |         |                DFS n1               |           |
   |         |<------------------------------------|           |
   |         |   store object    |        |        |           |
   |         |------------------>|        |        |           |
   |  done   |         |         |        |        |           |
   |<--------|         |         |        |        |           |
   |         |         |         |        |        |           |
   |      DHT: add location record "{object identifier} in IPFS n1"
   |         |------------------------------------------------>|

주요 변경 내용은 클라이언트가 오브젝트에 액세스하려고 할 때 발생한다. 아래 그림은 이러한 변경 사항을 보인다: Scale-Out NAS 로 인해 사이트의 모든 IPFS 노드는 동일 사이트의 다른 노드가 조작한 오브젝트를 볼 수 있다. 결과적으로 요청한 IPFS 노드에 관계없이 노드에서 오브젝트가 로컬에 저장되어 있는지 확인하면 Scale-Out NAS 에 요청하고 오브젝트가 자체적으로 작성된 것 처럼 찾는다. IPFS 원래 개념과 달리 사이트에서 로컬로 사용할 수 있는 오브젝트를 찾기위해 DHT 를 요청할 필요가 없다.

########## [reading of an object locally stored] ##########

[###################### <site1> #######################]   [<site2>]

+------+ +-------+ +-------+ +------+ +------+ +-------+   +-------+
|client| |IPFS n1| |IPFS n2| |DFS n1| |DFS n2| |DFS MDS|   |IPFS n3|
+------+ +-------+ +-------+ +------+ +------+ +-------+   +-------+
   |         |         |         |        |        |           |
   |   get   |         |         |        |        |           |
{object identifier}    |         |        |        |           |
   |-------->|         |         |        |        |           |
   |        get DFS Nodes storing {object identifier}          |
   |         |------------------------------------>|           |
   |         |                DFS n1               |           |
   |         |<------------------------------------|           |
   |         |   store object    |        |        |           |
   |         |------------------>|        |        |           |
  object="data"        |         |        |        |           |
   |<--------|         |         |        |        |           |
   |         |         |         |        |        |           |
  get {object identifier}        |        |        |           |
   |------------------>|         |        |        |           |
   |         |         |       get DFS Nodes       |           |
   |         |          storing {object identifier}            |
   |         |         |-------------------------->|           |
   |         |         |           DFS n1          |           |
   |         |         |<--------------------------|           |
   |         |         |         |        |        |           |
   |         |       read object |        |        |           |
   |         |         |-------->|        |        |           |
   |   object="data"   |         |        |        |           |
   |<------------------|         |        |        |           |

비슷한 방식으로 아래 그림은 클라이언트가 원격 사이트에 저장된 데이터에 액세스하는 경우의 프로토콜을 보인다. 클라이언트는 사이트의 모든 IPFS 노드에 요청을 보낸다. 노드는 분산 파일 시스템에서 오브젝트가 있는지 확인하고 오브젝트를 찾을 수 없기 때문에 DHT 에 복제본 찾기를 요청한다. 그런 후 오브젝트가 다운로드 되고 DHT 가 업데이트 되기 전 새로운 복제본이 로컬 Scale-Out NAS 에 저장된다. 이 사이트에서 수행되는 향후 액세스는 요청된 IPFS 노드에 관계없이 다른 사이트와 통신을 하지 않고 응답한다.

########## [reading of an object stored on a remote site] ##########

[################### <site1> ####################]   [<site2>]   [################### <site3> ###################]

+-------+ +-------+ +-------+ +-------+ +--------+   +-------+   +--------+ +-------+ +-------+ +-------+ +------+
|IPFS n1| |IPFS n2| |DFS1 n1| |DFS1 n2| |DFS1 MDS|   |IPFS n3|   |DFS2 MDS| |DFS2 n1| |IPFS n4| |IPFS n5| |client|
+-------+ +-------+ +-------+ +-------+ +--------+   +-------+   +--------+ +-------+ +-------+ +-------+ +------+
    |         |         |         |         |            |           |          |         |         |        |
    |         |         |         |         |            |           |          |        get {object identifier}
    |         |         |         |         |            |           |          |         |<-----------------|
    |         |         |         |         |            |           get DFS nodes storing          |        |
    |         |         |         |         |            |           | {object identifier}|         |        |
    |         |         |         |         |            |           |<-------------------|         |        |
    |         |         |         |         |            |           |  object not found  |         |        |
    |         |         |         |         |            |           |------------------->|         |        |
    |         |         |         |         |              DHT: locate {object identifier}          |        |
    |         |         |         |         |            |<-------------------------------|         |        |
    |         |         |         |         |            |           in IPFS n1           |         |        |
    |         |         |         |         |            |------------------------------->|         |        |
    |                        get/read {object identifier}                                 |         |        |
    |<------------------------------------------------------------------------------------|         |        |
    get DFS Nodes storing {object identifier}            |           |          |         |         |        |
    |-------------------------------------->|            |           |          |         |         |        |
    |                DFS n1                 |            |           |          |         |         |        |
    |<--------------------------------------|            |           |          |         |         |        |
    |    read object    |         |         |            |           |          |         |         |        |
    |------------------>|         |         |            |           |          |         |         |        |
    |                                         object="data"                               |         |        |
    |------------------------------------------------------------------------------------>|   object="data"  |
    |         |         |         |         |            |           |          |         |----------------->|
    |         |         |         |         |            |           |   get DFS Nodes    |         |        |
    |         |         |         |         |            |        to store {object identifier}      |        |
    |         |         |         |         |            |           |<-------------------|         |        |
    |         |         |         |         |            |           |       DFS2 n1      |         |        |
    |         |         |         |         |            |           |------------------->|         |        |
    |         |         |         |         |            |           |          store object        |        |
    |         |         |         |         |            |           |          |<--------|         |        |
    |         |         |         |         |          DHT add: "{object identifier} in IPFS n4"    |        |
    |         |         |         |         |            |<-------------------------------|         |        |
    |         |         |         |         |            |           |          |         |         |        |
    |         |         |         |         |            |           |          |         |  get {object identifier}
    |         |         |         |         |            |           |          |         |         |<-------|
    |         |         |         |         |            |       get DFS Nodes storing {object identifier}   |
    |         |         |         |         |            |           |<-----------------------------|        |
    |         |         |         |         |            |           |            DFS2 n1           |        |
    |         |         |         |         |            |           |----------------------------->|        |
    |         |         |         |         |            |           |          |    read object    |        |
    |         |         |         |         |            |           |          |<------------------|        |
    |         |         |         |         |            |           |          |         |        object="data"
    |         |         |         |         |            |           |          |         |         |------->|

이를 통해 IPFS 는 로컬 접속의 경우 “네트워크 containment” 속성을 충족시킬 수 있으며 네트워크 파티셔닝의 경우 각 사이트가 독립적으로 작동할 수 있다. IPFS 가 저장한 오브젝트는 불변이기 때문에 로컬 Scale-Out NAS 에 저장된 로컬 복제본이 오브젝트의 최신 버전인지 또는 다른 사이트에서 업데이트 된 버전을 찾을 수 있는지 확인하는 것은 신경쓰지 않는다.

########## summary of Fog characteristics met by IPFS and our proposal ##########

  IPFS Scale-Out NAS 와 결합된 IPFS
Data locality Yes Yes
Network containment No Only for local access
Disconnected mode Parially Yes
Mobility support Natively Natively
Scalability Yes Yes

요약하자면, 제안한 접근 방식은 클라이언트가 로컬 사이트에서 사용 가능한 복제본 중 하나가 있는 오브젝트를 요청할 때 DHT 가 사용되지 않기 때문에 로컬에 저장된 오브젝트에 액세스하기 위한 네트워크 트래픽을 제한한다. 다른 상황에서는 사이트 간 네트워크 트래픽의 양이 동일하다.

제안한 방식은 사이트를 구성하는 모든 노드에 저장된 데이터의 균형을 균일하게 유지한다. 클라이언트가 특정 IPFS 노드에 막대한 양의 데이터를 전송하는 경우 노드는 이러한 데이터를 표준 접근 방식으로 저장해야 하지만 우리의 제안에서는 사이트 내 Scale-Out NAS 를 구성하는 모든 스토리지 서버에 데이터가 분산된다.

3.1.3. Limitations

위 내용을 근거로 제시한 접근 방식의 성능이 크게 향상될 수 있음을 알 수 있다. 원격에서 저장된 오브젝트에 액세스하면 복제본이 저장된 모든 노드에서 오브젝트가 다운로드 된다. 이것은 가장 효율적인 방법으로 오브젝트를 다운로드하기 위한 IPFS 의 기본 동작이다. 노드가 오버로드되면 모든 노드가 응답할 수 있다.

Scale-Out NAS 를 사용하는 접근 방식에서는 사이트당 하나의 노드가 DHT 에서 오브젝트 복사본을 저장하는 것으로 알려져 있기 때문에 상황이 다르다. 클라이언트가 오브젝트를 쓰는 노드 또는 첫번째 노드 오브젝트에 액세스할 수 있다. 위 그림에서 볼 수 있듯 site1 에 있는 IPFS node4 는 오브젝트가 이전에 기록된 노드에 있으므로 site1 에 있는 IPFS node1 에서만 오브젝트를 다운로드 할 수 있으며 DHT 에서 오브젝트가 있는 것으로 알려진 노드다. IPFS node4 는 분산 파일 시스템을 IPFS node1 과 공유하면서 IPFS node2 에서도 오브젝트를 다운로드 할 수 있다는 사실을 알 길이 없다. 이러한 상황은 병목현상이나 일부 노드의 과부하로 이어질 수 있다. 마찬가지로 IPFS node1 에 접속할 수 없게되면 IPFS node2 를 전송의 소스로 사용할 수 있는 반면, IPFS node1 에 접속할 수 없게 된다.

이러한 문제의 해결책은 IPFS node 의 식별자가 아닌 현장의 식별자를 DHT 에 저장하는 것이 될 수 있다.

3.2. Reduction of inter-sites network traffic for accessing data stored on a remote site

이전 섹션에서 IPFS 를 각 사이트에 독립적으로 구축된 Scale-Out NAS 와 결합하여 로컬로 저장된 오브젝트에 액세스하는 동안 네트워크 트래픽을 억제하도록 제안하였다. 그러나 원격 사이트에 저장된 오브젝트에 접근하기 위해 DHT 의 사용은 사용자와 가까운 네트워크 트래픽을 포함하지 않으며 복제본에 가까운 오브젝트 위치를 저장하지 않는다. 다음 섹션에서 Fog 인프라에 대한 흥미로운 속성을 가진 도메인 네임 시스템 프로토콜을 제시하고 물리 토폴로지에 따라 구축된 트리에 의존하는 프로토콜을 소개한다.

3.2.1. Domain Name System protocol: an inspiration for our approach

DHT 나 다른 방식에서도 물리적 인접성을 제공하지 않고 오브젝트 복제본의 위치를 저장한 기록을 필요한 곳에 가깝게 재배치할 수 없기 때문에 DNS 에서 영감을 받은 프로토콜을 제안한다. 쿼리를 수행하는 확인자인 DNS 프로토콜에서 먼저 루트 노드를 요청하고 루트 노드가 쿼리에 직접 응답할 수 없는 경우 응답할 수 있는 서버가 확인자에게 표시된다. 이 메커니즘은 DHT 에서 수행되는 hop 방식과 유사하지만 차이가 있다: hash function 을 사용하는 대신 오브젝트 복제본의 위치를 저장하는 노드를 선택할 수 있다. 또한 Fog context 에서 매우 흥미로운 속성인 쿼리를 수행하기 위해 노드가 도달해야 할 서버를 제어할 수 있다. 또한 접속 시간을 줄이기 위해 DNS 캐시 메커니즘을 재사용하는 것은 유용한 방법이다.

3.2.2. Metadata management overview

DNS 프로토콜과 같은 방법으로 서로 다른 이름들이 계층적인 방식으로 조직된 다른 서버에 분산될 것을 제안한다. 이 트리는 Fog 에서 서로 다른 사이트로 구성되어 있으며 DNS 와는 반대로 현재 사이트에서 루트 노드까지 상향식으로 탐색된다. 위치가 지정된 수준에서 발견되지 않으면 상위 노드가 요청된다.

트리가 어떤 데이터라도 찾기위한 시간을 단축하는 궁극적인 목표로 네트워크의 물리적 토폴로지와 네트ㅝ크 지연시간에 따라 구축된다고 가정한다. 즉, 각 노드의 상위 노드가 물리적으로 가깝고 요청하여 오브젝트 위치를 찾는 것이 상위 노드의 상위 노드에 요청하는 것 보다 빠르다. 게다가 네트워크 트래픽을 토폴로지의 작은 부분으로 제한한다.

########## [Tree computed with our algorithm showing the initial content of the "location servers". Each site also has storage nodes and clients which are not represented] ##########

                                         +------------------------+
                                         |     city06 (site6)     |
                                         |- .city01 -> at "city01"|
                                         |- .city02 -> at "city02"|
                                         |- .city03 -> at "city03"|
                                         |- .city04 -> at "city04"|
                                         |- .city05 -> at "city05"|
                                         |- .city06 -> at "city06"|
                                         |- .city07 -> at "city07"|
                                         |- .city08 -> at "city08"|
                                         +------------------------+
                                               |     |  |    |
            +----------------------------------+     |  |    +----------------------------------+
            |                           +------------+  +-----------+                           |
            |                           |                           |                           |
+------------------------+  +------------------------+  +------------------------+  +------------------------+
|     city01 (site1)     |  |     city05 (site5)     |  |     city03 (site3)     |  |     city08 (site8)     |
|- .city01 -> at "city01"|  |- .city05 -> at "city05"|  |- .city03 -> at "city03"|  |- .city08 -> at "city08"|
|                        |  |- .city02 -> at "city02"|  |- .city04 -> at "city04"|  |                        |
|                        |  |-. city07 -> at "city07"|  |                        |  |                        |
+------------------------+  +------------------------+  +------------------------+  +------------------------+
                               |                |                   |
            +------------------+        +-------+                   |
            |                           |                           |
+------------------------+  +------------------------+  +------------------------+
|     city02 (site2)     |  |     city07 (site7)     |  |     city04 (site4)     |
|- .city02 -> at "city02"|  |- .city07 -> at "city07"|  |- .city04 -> at "city04"|
+------------------------+  +------------------------+  +------------------------+

위 그림은 가상의 네트워크 토폴로지에서 계산한 트리를 보여준다. 트리를 구축하는 방법은 다믕 섹션에서 설명한다. 위 그림에서 위치 기록에 대한 구성을 보여준다. 노드 사이의 edge 는 물리 네트워크 링크에 해당한다. 각 노드는 하위 트리에 저장된 오브젝트에 대한 모든 요청에 응답할 수 있으며, 특히 루트 노드는 모든 요청에 대한 응답을 제공할 수 있다. 루트 노드는 지리적 토폴로지에 따른 지연시간의 중심 위치이기 때문에 선택된다. 네트워크 대기 시간은 지리적 거리에 의해 좌우된다. 각 사이트는 “storage backend” 와 “location server” 로 구성되어 있다고 생각한다. “storage backend” 는 오브젝트를 저장하는 동시에 로컬에 저장되지 않은 다른 사이트 (예: 섹션 3.1 에 소개된 NAS 서버) 에서 오브젝트를 검색하는 역할을 겸한다. “location server” 는 복제본이 저장되는 하위 트리의 오브젝트 이름과 사이트 간의 연결을 저장하는 역할을 담당한다. 구체적으로 오브젝트 이름과 오브젝트 복제본을 저장하는 스토리지 노드의 주소로 구성된 위치 정보를 저장한다. 주어진 오브젝트에 대해 서버는 복제본 당 최대 하나의 레코드를 저장한다. 위 그림은 location server 의 초기 내용을 보여준다. 예를들어 * .city03 레코드는 .city03 프리픽스가 붙은 모든 오브젝트의 기본 위치를 정의한다. 이 특수 위치 기록의 장점은 다음 섹션에서 설명한다. 아래의 내용은 노드가 교환한 네트워크 메시지와 라우팅에 사용되는 물리 경로를 보여준다.

Object creation: 아래 그림은 클라이언트가 오브젝트를 작성할 때 오브젝트가 생성된 사이트에 해당하는 프리픽스가 오브젝트 이름에 추가되는 것을 보여준다. 그림에서 볼 수 있듯 위치 서버를 업데이트 하지 않는다. 와일드 카드 위임 (예: * .city03) 을 사용하면 오브젝트가 생성될 때 위치 정보가 업데이트되지 않고 추가 복제본이 추가될 때만 업데이트 된다. Fog Computing 비전에서 오브젝트가 생성된 사이트에서 대부분 읽힌다고 가정한다. 이것은 저장되는 위치 기록의 양을 크게 줄인다. 그럼에도 불구하고 오브젝트의 접미사 (suffix) 에만 의존하여 위치를 결정하는 것은 충분하지 않다. 사용자가 objectX.city03 에 액세스 하려고 할 때 city03 의 스토리지 노드에 직접 연결하면 안된다. 오브젝트의 복제본이 city03 에서 사용 가능하다는 것을 알고 있지만 네트워크에 더 가까운 복제본이 존재하지 않는지 확인하여야 한다. 여기서 접미사는 신규 오브젝트 복제본이 생성될 때 업데이트 메시지 양을 제한하는데만 사용된다.

########## [Sequence diagram of network traffic when a client writes an object in city03] ##########

                       city03

+------+     +---------------+     +---------------+
|client|     |storage backend|     |location server|
+------+     +---------------+     +---------------+
   |                 |                     |
    put objectX.city03            No location updated
   |---------------->|             The stored record
   |       done      |           *.city03 -> at "city03"
   |<----------------|          matches the object's name

Accessing an object from a remote site for the first time: 아래 그림은 city02 에서 city03 에 만들어진 오브젝트를 얻기위한 읽기 과정을 보여준다. 클라이언트가 로컬 스토리지 노드를 요청하기 시작한 다음 요청된 오브젝트가 로컬에 저장되지 않은 경우 이 노드는 오브젝트의 위치를 찾는다. 요청된 첫번째 위치의 서버는 가장 가까운 로컬 서버이다. 그런다음 위치가 존재하지 않은 경우 하나의 메타데이터 서버가 해당 위치에 응답할 때까지 저장 노드가 위치 서버의 부모 (city05) 를 요청한다. 최악의 경우 해당 위치는 루트 메타데이터 서버 (city06) 에서 발견된다. 최적 위치를 찾으면 city03 에 저장된 오브젝트가 로컬로 재배치되고 새로운 복제본이 만들어지기 때문에 위치 정보는 비동기적으로 업데이트 된다. 스토리지 노드는 위치가 발견된 서버와 가장 가까운 노드에서 location server 로 업데이트를 전송한다. 이러한 방식으로 업데이트된 “location server” 의 하위 트리에 있는 사이트는 향후 읽기에서 새로운 복제본을 찾을 수 있을 것이다. ‘위치 정보’ 를 사용하지 않고 사이트와 루트 노드 사이의 경로에 걸쳐 모든 오브젝트를 직접 복제하는 것이 가능할 수 있다는 점에 주목한다. 그러나 이것은 스토리지 공간 문제로 인해 구상할 수 없다.

########## [Read the object stored in city03 from city02] ##########

              city02                             city05              city06             city03

+------+     +-------+     +--------+          +--------+          +--------+          +-------+
|client|     |storage|     |location|          |location|          |location|          |storage|
|      |     |backend|     | server |          | server |          | server |          |backend|
+------+     +-------+     +--------+          +--------+          +--------+          +-------+
    |            |              |                   |                   |                  |
  get obejctX.city03            |                   |                   Object lookup phase
    |----------->|              |                   |                   |                  |
    |         where is objectX.city03?              |                   |                  |
    |            |------------->|                   |                   |                  |
    |            |  not found   |                   |                   |                  |
    |            |<-------------|                   |                   |                  |
    |            |     where is objectX.city03?     |                   |                  |
    |            |--------------------------------->|                   |                  |
    |            |            not found             |                   |                  |
    |            |<---------------------------------|                   |                  |
    |            |                where is objectX.city03?              |                  |
    |            |----------------------------------------------------->|                  |
    |            |                       at "city03"                    |                  |
    |            |<-----------------------------------------------------|                  |
    |            |                            get objectX.city03                           |
    |            |------------------------------------------------------------------------>|
    |            |                                   object                                |
    |   object   |<------------------------------------------------------------------------|
    |<-----------|              |                   |                   |                  |
   ===========================================================================================
    |            |              |                   |                   |                  |
    |            |---+          |                   |                  Object relocation phase
    |            |   |          |                   |                   |                  |
    |     store objectX.city03  |                   |                   |                  |
    |            |   |          |                   |                   |                  |
    |            |<--+          |                   |                   |                  |
    |      objectX.city03 -> at "city02"            |                   |                  |
    |            |------------->|                   |                   |                  |
    |              add objectX.city03 -> at "city02"                    |                  |
    |            |--------------------------------->|                   |                  |
    |            |           add objectX.city03 -> at "city02"          |                  |
    |            |----------------------------------------------------->|                  |

Accessing the object when several replicas are available: 아래 그림에서 city07 이 city03 에서 생성된 오브젝트를 요청하고 이전에 city02 에서 재배치 한 것을 보여준다. 읽기 과정은 앞과 동일하지만 city02 에 있는 복제본은 city05 에서 발견된 위치 기록 덕분에 접속할 수 있다. 루트 (city06) 메타데이터 서버에 도달하거나 업데이트 되지 않는 경우 이전 city02 에서 오브젝트 복제본이 추가되었음에도 불구하고 오브젝트의 이름은 수정되지 않는다는 것에 유의하여야 한다. city07 은 여전히 ‘.city03’ 접미사가 붙은 오브젝트를 찾지만, 트리에 저장된 위치 기록 덕분에 city02 에 저장된 더 가까운 복제본에 접근할 수 있다. 따라서 오브젝트 이름의 접미사는 읽기 과정에서 아무 의미가 없다. 사용자는 복제의 모든 위치가 아닌, 오브젝트가 처음 쓰여진 사이트만 알면된다. 이 접근 방법에는 몇가지 장점이 있다. i) 쓰기는 하지만 접근은 하지 않는 오브젝트에 대해서는 네트워크 트래픽이 생성되지 않는다. ii) 사이트 오브젝트에 접근하는 횟수가 많을수록 데이터 및 위치 기록의 복제본이 많아진다. iii) 오브젝트 복제본은 오브젝트 복제본의 위치를 얻는 노드의 하위 트리에서 발견된다. 결국, 위치가 가까울 수록 데이터는 가까워진다. 즉 이런 접근방식은 노드가 (트리 관점) 가장 가까운 복제본을 검색할 수 있도록 한다.

########## [Read from city07 the object previously read from city02] ##########

              city07                             city05              city06             city02

+------+     +-------+     +--------+          +--------+          +--------+          +-------+
|client|     |storage|     |location|          |location|          |location|          |storage|
|      |     |backend|     | server |          | server |          | server |          |backend|
+------+     +-------+     +--------+          +--------+          +--------+          +-------+
    |            |              |                   |                   |                  |
  get obejctX.city03            |                   |                   Object lookup phase
    |----------->|              |                   |                   |                  |
    |         where is objectX.city03?              |                   |                  |
    |            |------------->|                   |                   |                  |
    |            |  not found   |                   |                   |                  |
    |            |<-------------|                   |                   |                  |
    |            |     where is objectX.city03?     |                   |                  |
    |            |--------------------------------->|                   |                  |
    |            |            at "city02"           |                   |                  |
    |            |<---------------------------------|                   |                  |
    |            |                            get objectX.city03                           |
    |            |------------------------------------------------------------------------>|
    |            |                                   object                                |
    |   object   |<------------------------------------------------------------------------|
    |<-----------|              |                   |                   |                  |
  ===========================================================================================
    |            |              |                   |                   |                  |
    |            |---+          |                   |                  Object relocation phase
    |            |   |          |                   |                   |                  |
    |     store objectX.city03  |                   |                   |                  |
    |            |   |          |                   |                   |                  |
    |            |<--+          |                   |                   |                  |
    |      objectX.city03 -> at "city07"            |                   |                  |
    |            |------------->|                   |                   |                  |
    |             add objectX.city03 -> at "city07"                     |                  |
    |            |--------------------------------->|                   |                  |

Deleting a single replica or removing an object entirely: 단일 복제본을 삭제하려면 복제본을 저장하는 사이트에서 복제본을 가리키는 위치 레코드를 저장하지 않는 첫번째 사이트로 트리를 검색하는 것이 제안되는 전략이다. 삭제된 특정 복제본을 가리키는 사이의 모든 위치 정보가 제거된다. 그러나 노드가 하위 트리에 다른 복제본이 저장되어 있는지 모르는 불일치로 이어질 수 있다. 이것이 트리 위층에 위치 기록을 복사하는 것을 제안하는 이유이다. 예를들어 city02 에 위치한 복제본을 삭제하기 위해 위치 기록 objectX.city03->”city02” 는 city02 와 city05 및 city06 의 location server 에서 제거된다. 그럼에도 불구하고 city05 의 location server 는 city07 을 가리키는 오브젝트에 대한 기록도 가지고 있기 때문에 city06 에서 city07 을 가리키는 신규 기록을 추가한다. 오브젝트의 “master copy” 을 제거하는 경우, 트리를 현재 노드에서 루트 노드로 탐색할 수 있으며, 루트 노드에 저장된 위치 정보가 오브젝트의 와일드카드가 아닌 경로의 각 서버에 재복사할 수 있다. 예를들어 city03 에 저장된 복제본을 삭제하면 city03 에 objectX.city03->”city02” 기록을 삽입할 수 있다.

########## [Delete a single object replica (city02)] ##########

              city02                             city05              city06

+------+     +-------+     +--------+          +--------+          +--------+
|client|     |storage|     |location|          |location|          |location|
|      |     |backend|     | server |          | server |          | server |
+------+     +-------+     +--------+          +--------+          +--------+
    |            |              |                   |                   |
delete objectX.city03           |                   |                   |
    |----------->|              |                   |                   |
    |            |---+          |                   |                   |
    |            |   |          |                   |                   |
    |  delete objectX.city03    |                   |                   |
    |            |   |          |                   |                   |
    |    done    |<--+          |                   |                   |
    |<-----------|              |                   |                   |
    |         where is objectX.city03?              |                   |
    |            |------------->|                   |                   |
    |              at "city02"                      |                   |
    |            |<-------------|                   |                   |
    |   delete objectX.city03 -> at "city02"        |                   |
    |            |------------->|                   |                   |
    |            |     where is objectX.city03?     |                   |
    |            |--------------------------------->|                   |
    |            |     at "city02" and "city07"     |                   |
    |            |<---------------------------------|                   |
    |            delete objectX.city03 -> at "city02"                   |
    |            |--------------------------------->|                   |
    |            |               where is objectX.city03?               |
    |            |----------------------------------------------------->|
    |            |                      at "city02"                     |
    |            |<-----------------------------------------------------|
    |            |           delete objectX.city03 -> at "city02"       |
    |            |----------------------------------------------------->|
    |            |            add objectX.city03 -> at "city07"         |
    |            |----------------------------------------------------->|

모든 복제본을 제거하는데 구성된 오브젝트를 완전히 삭제하려면 루트 노드에서 트리를 검색하고 이 오브젝트에 대해 발견된 모든 위치 정보를 따라 삭제한다. 와일드카드 기록은 따라갈 수 있지만 다른 오브젝트에도 사용되기 때문에 삭제하지 않는다.

########## [Delete a "master copy" (city03)] ##########

              city03                             city06

+------+     +-------+     +--------+          +--------+
|client|     |storage|     |location|          |location|
|      |     |backend|     | server |          | server |
+------+     +-------+     +--------+          +--------+
    |            |              |                   |
delete objectX.city03           |                   |
    |----------->|              |                   |
    |            |---+          |                   |
    |            |   |          |                   |
    |  delete objectX.city03    |                   |
    |            |   |          |                   |
    |    done    |<--+          |                   |
    |<-----------|              |                   |
    |            |     where is objectX.city03?     |
    |            |--------------------------------->|
    |            |           at "city07"            |
    |            |<---------------------------------|
    |     add objectX.city03 -> at "city07"         |
    |            |------------->|                   |

설명한 프로토콜이 현재 노드에서 루트 노드로 가는 물리적 경로를 따라 발견되기 때문에 DHT 보다 Fog 인프라에 더 적합하다고 주장한다. 위치 정보를 생성하면 조회 지연 시간을 줄일 수 있을 뿐만 아니라 네트워크 파티셔닝 시 사이트에 도달할 수 있는 오브젝트 복제본을 찾을 수 있어 Fog 사이트 자율성이 높아진다. 이 프로토콜은 오브젝트를 찾는 동안 교환되는 네트워크 트래픽 (대부분 log(N) 노드는 트리가 균형적일 때 접촉됨) 을 제한하고 접속 시간에 미치는 영향을 제한한다. 두번째 장점은 복제되지 않은 오브젝트가 와일드카드로 인해 특정 위치 기록이 없기 때문에 필요한 위치 기록의 복제본을 최소로 제한한다는 점이다. 마지막으로, 각 노드는 토폴로지에 대한 제한된 정보를 가지고 있다. 각 노드는 트리의 상위 노드만 알고있다.

3.2.3. Algorithm to build the tree

제안된 프로토콜은 트리 구성에 의존한다. 트리 구성에 있어 세부설명은 다음 섹션에서 소개한다. 플랫 트리는 루트 노드에 직접 도달하기 때문에 노드가 새 위치 스토리지 복제본의 장점을 살릴 수 없다. 이와 반대로 딥 트리 토폴로지는 수 많은 홉 구성으로 인해 성능이 저하된다. 실제 트리 구조는 오브젝트를 찾을 수 있는 최대 홉 수를 결정하지만 다른 노드가 가까운 오브젝트 복제본을 찾을 수 있는 기회와 이를 찾는 대기 시간도 결정한다.

소스 노드에서 다른 모든 노드로 최단 경로를 계산하는 고전적인 알고리즘은 Dijkstra 알고리즘이다. 소스 노드에서 다른 노드로 최단 경로 목록은 소스 노드가 루트인 트리로 볼 수 있다. Dijkstra 알고리즘의 단점은 루트 노드를 지정한다는 것이다. “best” 루트 노드를 선택하기 위해 각 노드를 소스로 사용하여 트리를 연속적으로 계산하고 가중치가 낮은 것을 선택한다.

예를 들어 아래 그림에서 트리의 가중치는 9.0+7.0+4.0+5.0+5.0+(2.5+4.0)+(4.5+5.0)=46 이다.

########## [Dijkstra with the traditional cost function] ##########

                                  +--------------+
       +--------------------------|city06 (site6)|-------------------------+
       |                          +--------------+                         |
       |                            |    |     |                           |
       |                +-----------+    |     +----------+                |
       |                |                |                |                |
     9.0ms            7.0ms            4.0ms            5.0ms            5.0ms
       |                |                |                |                |
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+
|city02 (site2)| |city01 (site1)| |city05 (site5)| |city03 (site3)| |city08 (site8)|
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+
                                         |                |
                                       2.5ms            4.5ms
                                         |                |
                                  +--------------+ +--------------+
                                  |city07 (site7)| |city04 (site4)|
                                  +--------------+ +--------------+

아래 그림에서 보이는 트리는 총 지연 시간을 최적화하지만 매우 평평하며 대부분 노드가 재배치 없이 루트에 직접 액세스한다.

########## [Dijkstra with our cost function] ##########

                                          +--------------+
       +----------------------------------|city06 (site6)|----------------------------------+
       |                                  +--------------+                                  |
       |                                    |  |    |  |                                    |
       |                +-------------------+  |    |  +-------------------+                |
       |                |                +-----+    +-----+                |                |
       |                |                |                |                |                |
     9.0ms            7.0ms           10.0ms            4.0ms            5.0ms            5.0ms
       |                |                |                |                |                |
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+ +--------------+
|city02 (site2)| |city01 (site1)| |city04 (site4)| |city05 (site5)| |city03 (site3)| |city08 (site8)|
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+ +--------------+
                                                          |
                                                        2.5ms
                                                          |
                                                   +--------------+
                                                   |city07 (site7)|
                                                   +--------------+

아래 그림에서 루트가 조금이라도 늘어날 때까지 모든 조상 노드에 도달하는 대기 시간이 길어도 깊은 노드는 위치 기록을 찾을 가능성이 더 크다.

########## [Dijkstra with our relaxed cost function] ##########

                         +--------------+
       +-----------------|city06 (site6)|-----------------+
       |                 +--------------+                 |
       |                       |  |                       |
       |                +------+  +------+                |
       |                |                |                |
     7.0ms            4.0ms            5.0ms            5.0ms
       |                |                |                |
+--------------+ +--------------+ +--------------+ +--------------+
|city01 (site1)| |city05 (site5)| |city03 (site3)| |city08 (site8)|
+--------------+ +--------------+ +--------------+ +--------------+
                     |      |            |
       +----5.0ms----+    2.5ms          4.5ms
       |                    |            |
+--------------+ +--------------+ +--------------+
|city02 (site2)| |city07 (site7)| |city04 (site4)|
+--------------+ +--------------+ +--------------+

3.5. Conclusion and Discussion

지금까지 로컬로 저장된 오브젝트가 요청될 때 사이트 간 네트워크 교환을 줄이는 방법을 제안했다. IPFS 를 Scale-Out NAS 와 결합하여 각 사이트에 저장된 모든 오브젝트를 사이트 전체 IPFS 노드에서 사용할 수 있도록 제안하였다. 또한 물리 네트워크 토폴로지를 고려하여 오브젝트 위치 관리에 사용되는 DHT (메타데이터 관리) 를 Dijkstra 알고리즘의 수정된 버전으로 구축된 트리에 의존하는 프로토콜로 교체하여 원격으로 저장된 오브젝트에 접속할 때 사이트간 네트워크 트래픽을 줄이는 방안을 제안하였다.

제안된 프로토콜에 추가적으로 필요한 개선점은 불변 오브젝트가 있는 경우 사용자가 자신의 데이터를 수정할 수 있도록 하는 것이다. 하지만 수정은 다른 모든 복제본을 수정해야 하기 때문에 일관성을 관리하는 것은 매우 어려운 일이다. 이것은 접속 시간에 대한 영향을 제한하기 위해 비동기적으로 수행될 수 있지만, 제안된 프로토콜은 최신 버전에 가까운 복제본을 찾기 위한 프로토콜로 수정되어야 한다.

제안된 Fog 아키텍처는 대칭 또는 역방향 CDN 으로 간주될 수 있다. CDN 은 사용자와 가까운 곳에 위치한 서버의 데이터를 캐싱하는 방식으로 구성된다. 여기에 두가지 장점이 있다: i) 근접 서버에 접속하면 요청된 자원에 대한 액세스 시간을 줄일 수 있으며, ii) 모든 클라이언트가 아닌 캐싱 서버에만 콘텐츠를 전송하면 되기 때문에 중앙 서버 부하를 줄일 수 있다. 이러한 네트워크는 표준 아키텍처가 없다. 일부는 트리 hash function 에 의존하는 반면 다른 일부는 DHT 에 의존하고 일부는 하이브리드로 다른 프로토콜의 혼합에 의존한다.

몇몇 저자들이 Fog 계층 구조는 가까운 곳에 오브젝트 복제본이 즉시 작성되는콘텐츠 배포 네트워크로 간주될 수 있다. 예를들어 Yang 등의 경우, 네트워크 edge 에 있는 스토리지 서버를 사용하여 클라우드에 저장된 데이터를 캐싱하는데 이것은 제안한 것과 유사한 접근 방식이다. 그러나 Fog 컴퓨팅용 CDN 과 스토리지 솔루션의 주요 차이점은 CDN 에서 데이터가 네트워크 코어에 저장되어 edge 에 전파되는 반면, Fog 는 edge 에 데이터가 생성된다는 것이다. 이러한 의미로 Fog 컴퓨팅은 클라이언트에서 전송된 데이터가 클라우드에 도달할 때 까지 모든 계층을 통과하는 거꾸로된 CDN 으로 볼 수 있다.

또한 제시한 접근 방식은 네트워크 오버레이를 사용하지 않기 때문에 ICN 과도 비교될 수 있다. ICN 과 NDN 또는 NNC 는 요청 데이터를 저장하는 노드로 요청을 직접 라우팅하기 위해 네트워크를 사용하는 개념이다. 다른 방식과는 달리 데이터에 접근하기 전 데이터를 찾을 필요가 없다는 것이다. 클라이언트가 특정 컴퓨터가 아닌 데이터의 대상으로 요청을 보내고 네트워크는 이것을 저장하고 있는 컴퓨터로 전송한다. 이것에 대한 몇 구현이 제안되었다. 일부는 데이터센터 내에서 작업하는 것으로 전문화되었고, 다른 일부는 멀티사이트 환경 특히 CDN 네트워크에서 작업하도록 조정되었다. 이 방식의 주요 장점은 네트워크에 저장된 다른 오브젝트를 찾기위해 메타데이터 서버나 어떤 프로토콜도 요구하지 않고 접근 시간을 향상시키는 것이다. 이런 의미에서 이 접근 방식은 데이터를 Fog 컴퓨팅 아키텍처를 저장하는데 사용될 수 있다. 그러나 각 라우터에서 각 오브젝트의 위치를 저장하는 테이블을 유지하는 것은 비용이 많이든다.

다음 섹션에서 사이트 간 교환되는 네트워크 트래픽 양 뿐만 아니라 접속 시간에 미치는 영향을 측정하기 위해 제안사항을 실험 평가한다.


원문 링크: docker document (URL: https://docs.docker.com/machine/overview/)

DOCKER MACHINE OVERVIEW

Docker Machine 을 사용하면 다음을 수행할 수 있다:

  • MAC 또는 Windows 에서 Docker 설치 및 실행
  • 여러 원격 Docker 호스트 프로비저닝 및 관리
  • 스웜 (Docker Swarm) 클러스터 제공

Docker Machine 은 사용자의 머신이 아닌 클라우드 컴퓨팅 VM 을 비롯한 원격지의 서버에 Docker Engine 을 설치할 수 있도록 하고 명령어를 통해 존재하지 않는 머신을 새로 만들어서 설치해 주는 도구이다.

DOCKER MACHINE

Not In My BackYard, But on the Cloud!

1. What is Docker Machine?

가상 호스트에 Docker Engine 을 설치하고 docker-mashine 명령으로 호스트를 관리할 수 있는 도구이다. 이것을 사용하여 로컬 호스트 (MAC, Windows), 회사 네트워크, 데이터 센터 또는 클라우드 공급자 (Azure, AWS 또는 DigitalOcean 등) 에서 Docker 호스트를 생성할 수 있다.

docker-machine 명령을 사용하면 다음과 같은 일을 할 수 있다:

  • 호스트 실행 (start), 검사 (inspect), 중지 (stop), 재실행 (restart)
  • Docker Client 및 Daemon 업그레이드
  • 호스트와 통신할 수 있도록 Docker Client 구성

Machine CLI 를 실행중인 호스트에서 docker 명령을 직접 실행할 수 있다. 예를들어 docker-machine env default 를 실행하여 ‘default’ 호스트를 가리키게 하고 화면에 보이는 지시를 따라 env 설정을 완료한 다음 docker psdocker run hello-world 등을 실행한다.

Docker v1.12 부터 MACWindows 의 앱에 ‘Docker Compose’ 및 ‘Docker Machine’ 이 포함되어 설치 가능하다.

2. Why should I use it?

Docker Machine 을 사용하면 다양한 Linux 버전에서 여러 원격 Docker 호스트를 프로비저닝 할 수 있다. (MAC 또는 Windows 시스템에서 Docker 를 실행할 수 있다.)

Docker Machine 에는 두가지 사용 사례가 있다:

  • 구형 데스크탑이 있고 MAC 또는 Windows 에서 Docker 를 실행

MAC 또는 Windows 기반 시스템에서 Docker Engine 을 로컬로 실행하기 위해 Docker Machine 이 필요하다. Docker Toolbox 를 사용하여 Docker Machine 을 설치하면 Docker Engine 을 사용하여 로컬 가상 머신을 프로비저닝하고 연결하고 docker 명령을 실행할 수 있다.

  • 원격 시스템에서 Docker 호스트를 프로비저닝

Docker Engine 은 기본적으로 Linux 시스템에서 실행된다. Docker Engine 을 다운로드하고 설치만 하면 docker 명령을 실행할 수 있다. 그러나 네크워크, 클라우드 또는 로컬의 여러 Docker 호스트를 효율적으로 프로비저닝 하려면 Docker Macnine 이 필요하다.

‘Docker Machine’ 을 설치하면 기본 시스템의 OS (MAC, Windows, Linux) 에 구애받지 않고 docker-machine 명령을 사용하여 많은 Docker 호스트를 프로비저닝하고 관리할 수 있다. 자동으로 호스트를 생성하고 Docker Engine 을 설치한 다음 docker client 를 구성한다. 각 관리 호스트 (“machine”) 는 Docker 호스트에 구성된 클라이언트의 조합이다.

3. What’s the differece between Docker Engine and Docker Machine?

일반적으로 “Docker” 라고 함은 Docker Engine, Docker Daemon 그리고 Daemon 과 상호 작용을 위한 인터페이스를 지정하는 REST API 및 Daemon 과 통신하는 CLI 클라이언트로 구성 (REST API 를 사용) 된다.

Docker Engine 은 CLI 에서 docker run <image>, docker ps, docker image ls 와 같이 docker 명령을 수행한다.

Docker Machine 은 Dockerized 호스트 (Docker Engine 이 있는 호스트) 를 프로비저닝하고 관리하기 위한 도구이다. 로컬 시스템에 Docker Machine 을 설치하면 되는데 Docker Machine 은 자체 CLI 인 docker-machine 과 Docker Engine 클라이언트 인 docker 가 있다.

Machine 을 사용하여 하나 이상의 가상 시스템에 Docker Engine 을 설치할 수 있다. 가상 시스템은 로컬 (MAC 또는 Windows 에서 Machine 을 사용하여 Docker Engine 설치) 또는 원격 (클라우드 제공자의 Machine 을 사용하여 Dockerized 호스트를 프로비저닝) 일 수 있다.

Dockerlized 호스트 자체는 관리되는 “Machine” 이다.

4. Install Docker Machine

다음과 같은 순서로 Docker Machine 을 설치한다. (Linux 환경 가정)

다른 OS 의 경우 다음 링크 참조 (URL: https://docs.docker.com/machine/install-machine/)

1) Docker Install

2) PATH 설정

$ base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  chmod +x /usr/local/bin/docker-machine


  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   617  100   617    0     0   1465      0 --:--:-- --:--:-- --:--:--  1462
100 26.8M  100 26.8M    0     0  2225k      0  0:00:12  0:00:12 --:--:-- 1654k

Docker Machine 의 경우 Github 에서 배포하고 있기 때문에 curl 명령을 사용하여 다운로드 한다.

Docker Machine 은 Docker Engine 과 같이 시스템 권한으로 동작하는 서비스가 아니다. 그래서 혼자만 사용하는 경우 시스템 경로 (/usr, /usr/local, … ) 에 설치할 이유는 없다. 하지만 가능하면 공식 문서에 소개된 것 처럼 /usr/local 에 설치하도록 하자.

Docker github 페이지 를 참조하여도 된다. (URL: https://github.com/docker/machine/releases)

3) Docker Machine 동작 확인

$ docker-machine version
docker-machine version 0.16.0, build 702c267f

4-1. Install bash completion scripts

Machine repository 는 다음과 같은 기능을 추가하는 bash 스크립트를 제공한다:

  • command completion
  • 쉘 프롬프트에 동작중인 머신을 표시
  • docker-machine use 명령을 통한 동작 머신 전환

버전을 확인하고 스크립트를 /etc/bash_completion.d 또는 /usr/local/etc/bash_completion.d 에 저장한다.

파일명을 docker-machine-prompt.bash 으로 하고 위치는 /etc/bash_completion.d 으로 한다.

base=https://raw.githubusercontent.com/docker/machine/v0.16.0
for i in docker-machine-prompt.bash docker-machine-wrapper.bash docker-machine.bash
do
  sudo wget "$base/contrib/completion/bash/${i}" -P /etc/bash_completion.d
done

bash 터미널에서 source /etc/bash_completion.d/docker-machine-prompt.bash 를 실행하여 이전에 다운로드 한 docker-machine-prompt.bash 파일을 찾을 수 있는 위치를 설정한다.

docker-machine 쉘 프롬프트를 활성화하려면~ / .bashrcPS1 설정에$ (__ docker_machine_ps1)을 추가하여야 한다.

PS1='[\u@\h \W$(__docker_machine_ps1)]\$ '

위 내용은 github 에 script 가 제공되고 있으니 활용하여도 된다. (URL: https://github.com/docker/machine/tree/master/contrib/completion/bash)

script 를 사용하여 설치가 끝나면 bash 를 적용하기 위해서 쉘을 다시 열어야 한다.

$ docker-machine <TAB>
active            env               ip                mount             restart           ssh               stop              use
config            help              kill              provision         rm                start             upgrade           version
create            inspect           ls                regenerate-certs  scp               status            url

docker-machine 명령어 뒤에 탭 (TAB) 을 해보면 다음으로 올 수 있는 보조명령, 옵션, 값 등이 보여진다.

4-2. How to uninstall Docker Machine

Docker Machine 을 제거하려면 다음을 수행한다:

  • 작성된 Machine 들을 선택하여 제거한다.
    • 각 Machine 을 개별적으로 제거하려면: docker-machine rm <machine-name>
    • 모든 Machine 을 제거하려면: docker-machine rm -f $(docker-machine ls -q) (Windows 의 경우 -force 를 사용해야할 수 있음)
    • 기존 시스템을 MAC 또는 Windows 용 환경으로 저장하고 마이그레이션 하는 경우가 있으므로 시스템 제거는 선택적
  • 실행파일을 제거: rm $(which docker-machine)

Note: docker-machine 에 의해 생성한 각 가상 머신과 관련된 config.json, 인증서 및 기타 데이터는 MAC 또는 Linux 의 ~/.docker/machine/machines/ 에 위치하며 Windows 는 ~\.docker\machine\machines\ 에 위치한다. 이러한 파일은 로컬 또는 원격 서버에 관계없이 Docker CLI 에 대한 정보에만 영향을 주기 때문에 해당 파일을 직접 편집하거나 제거하지 않는 것이 좋다.


Make my Docker Image

나만의 콘테이너가 필요한 경우 콘테이너가 사용할 이미지를 만들어야 되는데 간단하게 만들어보자.

Hello World

모든 언어의 시작이 ‘Hello World’ 로 시작하듯 간단하게 프로그램을 작성하자.

파일명은 ‘hello.c’ 로 할 것이다.

#include <stdio.h>

int main() {
    printf("hello from docker container\n");
    return 0;
}

컴파일을 위한 ‘Makefile’ 을 만들어야 하는데 이는 콘테이너가 실행하면서 ‘hello.c’ 를 컴파일하기 때문이다.

중요한 점은 ‘hello.c’ 코드를 static 하고 실행단계에서 C library 에 의존하지 않도록 컴파일 하여야 한다.

CC	= gcc
CFLAGS	= -static -Wall

hello: hello.c
    $(CC) $(CFLAGS) $< -o $@

c 코드이며 Makefile 을 사용하였기에 호스트에서 컴파일 하기 위해서는 ‘gcc’ 와 ‘make’ 가 필요하다.

$ sudo apt install -y gcc make

준비가 되었으면 컴파일 한다.

$ make
gcc -static -Wall hello.c -o hello

정상적으로 파일이 컴파일 되었는지 확인한다.

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=05cb203367c91510838cd5c808889cf528026a5d, not stripped

확인 결과 ..., statically linked, ... 를 확인하였다면 의존성 문제는 없는 것이다.

Make Docker Image

위 예에서 사용한 make 는 복잡한 의존성 관계를 지닌 프로그램을 컴파일 할 때 Makefile 에 포함된 내용에 의해 단순화 된다.

즉, 개발자가 1) 길고 복잡한 명령을 외우지 않도록 명령어 집합을 포함하고, 2) 여러 명령이 순서에 맞도록 나열되어 있고, 3) 의존성에 따라 구조적인 절차가 포함되어 있다.

Docker 에서는 Dockerfile 이 같은 역할을 담당한다.

위에서 예를 든 ‘hello.c’ 를 포함한 Container Image 를 만드는 과정이 포함된 절차를 적어둔 파일이다.

FROM scratch
COPY hello /
CMD ["/hello"]

각 절차의 의미는 다음과 같다.

  1. FROM scratch: 비어있는 이미지 (스크레치)
  2. COPY hello /: hello 파일을 / 에 복사
  3. CMD ["/hello"]: 실행할 명령은 /hello

생성한 Dockerfile 을 사용하여 docker build 를 한다. (docker builder 명령어 끝에 . 이 포함됨에 주의)

$ docker build -t hello .
Sending build context to Docker daemon  849.4kB
Step 1/3 : FROM scratch
 --->
Step 2/3 : COPY hello /
 ---> fa32a7a28dc7
Step 3/3 : CMD ["/hello"]
 ---> Running in b28638619810
Removing intermediate container b28638619810
 ---> 8dfc72a052e2
Successfully built 8dfc72a052e2
Successfully tagged hello:latest

docker build 명령은 Dockerfile 을 사용하여 이미지를 만드는 것이다. 작성한 3 줄의 Dockerfile 명령을 하나씩 실행하면서 이미지를 만들어가는 것이 로그에 남는다.

Removing intermediate container b28638619810 라는 구문을 보니 intermediate container 를 삭제하는 것을 볼 수 있다.

Check First Docker Image

만들어진 Image 가 정상동작하는지 확인하기 위해 다음을 실행한다.

$ docker run hello
hello from docker container

hello.c 에서 출력하고자 하는 결과가 나타나는 것을 확인할 수 있다.

작성한 image 정보를 확인해보면 다음과 같다.

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              8dfc72a052e2        6 minutes ago       845kB

$ docker container ls -al
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
44f26bfbac29        hello               "/hello"            2 minutes ago       Exited (0) 2 minutes ago                       lucid_kalam

REPOSITORY 는 hello, TAG 는 latest, IMAGE ID 는 8dfc72a052e2 인 image 가 생성되었음을 확인할 수 있다.

또한, 이 image 를 사용한 Container 는 2 분 전에 만들어져 /hello 명령을 실행하고, 2 분 전에 종료되었음을 확인할 수 있다.


Hello World

docker 는 “hello world” 를 제공하고 있다. 대부분 컴퓨팅 언어를 하면서 처음 접하게 되는 단순한 프로그램인데 “Hello World” 를 프린팅하는 예제이다.

docker run hello-world 명령어를 입력하는 것으로 실행된다.

$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Docker Image and Registry

위의 예를 설명하면 다음과 같다.

  • Unable to find image 'hello-world:latest' locally: 로컬 저장소에서 hello-world 이미지를 찾을 수 없음
  • latest: Pulling from library/hello-world: latest 버전을 다운로드 하고있음
  • 1b930d010525: Pull complete: 다운로드가 완료됨
  • Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f: 다운로드 콘텐츠 체크
  • Status: Downloaded newer image for hello-world:latest: 다운로드가 완료되었음

로컬 저장소에 원하는 이미지가 없는 경우 외부에서 해당 이미지를 찾고 다운로드 하는 것을 볼 수 있다.

docker 는 docker HUB 라고 하는 registry 를 통하여 이미지를 로컬에 다운로드 한 후 이것을 활용하여 동작한다.

DOCKER REGISTRY

docker image 를 저장하는 중앙저장소 객체는 versioning, tagging 됨

위의 예를 계속 설명하면

  1. docker client 가 docker daemon 에 접속함
  2. docker daemon 은 hello world 이미지를 Docker Hub 를 통해 받음
  3. docker daemon 은 받은 이미지를 사용하여 컨테이너를 만들고 컨테이너에서 실행된 실행파일이 메시지 출력을 함
  4. docker daemon 은 출력을 docker client 에게 전달하였고 이것을 당신의 터미널로 보냄

Docker Ubuntu Image and Registry

  • docker run -it ubuntu bash 명령어로 실행
$ docker run -it ubuntu bash

Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu

5c939e3a4d10: Pulling fs layer
c63719cdbe7a: Downloading 10.17MB/26.69MB
19a861ea6baf: Pull complete
651c9d2d6c4f: Waiting
...
5c939e3a4d10: Extracting [=================================================> ]  26.25MB/26.69M
c63719cdbe7a: Extracting [=======================================>           ]  16.25MB/26.69M
19a861ea6baf: Pull complete
651c9d2d6c4f: Pull complete
...
5c939e3a4d10: Pull complete
c63719cdbe7a: Pull complete
19a861ea6baf: Pull complete
651c9d2d6c4f: Pull complete
Digest: sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110
Status: Downloaded newer image for ubuntu:latest
root@b7da2785780e:/#

ubuntu 컨테이너를 실행하는 위 예를 단계별로 설명하면 다음과 같다.

  • Pulling fs layer
  • Downloading
  • Extraction

1. Layered Image

큰 이미지인 ubuntu 를 다운로드 하는데 4 단계로 구성되어 있다. Pulling fs layer 라는 의미에서 알 수 있듯 docker 가 사용하는 disk image 는 계층적으로 구성되어 있다는 의미이다.

쉽게 말하자면 ubuntu 버전이 업데이트 됨에 따라 각 버전들이 레이어로 구성되어 있는 것이며 각 레이어는 업데이트 내용을 포함하고 있다는 것이다.

Docker Image

Docker Image 는 단계적으로 Layered Image

2. Execution

위의 예에서 docker run -it ubuntu bash 를 실행하면

$ docker run -it ubuntu bash
root@b7da2785780e:/#

와 같이 다른 출력이 없이 ubuntu 컨테이너의 root 프롬프트가 실행된 것을 확인할 수 있다.

이와 같은 것을 대화형 모드라고 하는데 이것은 -i, -t 옵션을 사용한 결과이다.

...
-i, --interactive                    Keep STDIN open even if not attached
-t, --tty                            Allocate a pseudo-TTY
...

기본적으로 컨테이너는 해당하는 명령을 수행하고 빠져온다. (이는 hello-world 예에서 확인할 수 있다.)

아래는 ubuntu 컨테이너를 실행하고 디렉토리 구조를 확인하는 명령을 실행시킨 예를 보여준다. (ls 명령을 실행하여 디렉토리 구조를 확인할 수 있다.)

$ docker run -it ubuntu ls -l

total 64
drwxr-xr-x   2 root root 4096 Jan 12 21:10 bin
drwxr-xr-x   2 root root 4096 Apr 24  2018 boot
drwxr-xr-x   5 root root  360 Feb 17 11:21 dev
drwxr-xr-x   1 root root 4096 Feb 17 11:21 etc
drwxr-xr-x   2 root root 4096 Apr 24  2018 home
drwxr-xr-x   8 root root 4096 May 23  2017 lib
drwxr-xr-x   2 root root 4096 Jan 12 21:10 lib64
drwxr-xr-x   2 root root 4096 Jan 12 21:09 media
drwxr-xr-x   2 root root 4096 Jan 12 21:09 mnt
drwxr-xr-x   2 root root 4096 Jan 12 21:09 opt
dr-xr-xr-x 109 root root    0 Feb 17 11:21 proc
drwx------   2 root root 4096 Jan 12 21:10 root
drwxr-xr-x   1 root root 4096 Jan 16 01:20 run
drwxr-xr-x   1 root root 4096 Jan 16 01:20 sbin
drwxr-xr-x   2 root root 4096 Jan 12 21:09 srv
dr-xr-xr-x  13 root root    0 Feb 17 11:21 sys
drwxrwxrwt   2 root root 4096 Jan 12 21:10 tmp
drwxr-xr-x   1 root root 4096 Jan 12 21:09 usr
drwxr-xr-x   1 root root 4096 Jan 12 21:10 var
$

컨테이너가 실행되고 명령을 수행한 뒤 컨테이너가 종료됨을 확인할 수 있다.

3. Namespace

컨테이너는 Namespace 를 활용하여 격리한다고 한다.

$ docker run -it ubuntu bash

root@810699d1fe17:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@810699d1fe17:/# pwd
/
root@810699d1fe17:/# du -h --max-depth=1 / 2> /dev/null | sort -hr
70M	/
43M	/usr
13M	/lib
5.3M	/var
4.8M	/bin
3.8M	/sbin
620K	/etc
20K	/run
12K	/root
4.0K	/tmp
4.0K	/srv
4.0K	/opt
4.0K	/mnt
4.0K	/media
4.0K	/lib64
4.0K	/home
4.0K	/boot
0	/sys
0	/proc
0	/dev
root@810699d1fe17:/#

디렉토리 구조, 루트 사용자, 디스크 사용량이 70M 임을 확인할 수 있다.

root@810699d1fe17:/# ps axu
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  18508  3280 pts/0    Ss   00:46   0:00 bash
root        13  0.0  0.1  34400  2728 pts/0    R+   00:50   0:00 ps axu
root@810699d1fe17:/# w
 00:50:52 up 5 min,  0 users,  load average: 0.00, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root@810699d1fe17:/# ls /var/log
alternatives.log  apt  bootstrap.log  btmp  dpkg.log  faillog  lastlog  tallylog  wtmp
root@810699d1fe17:/# lastlog
Username         Port     From             Latest
root                                       **Never logged in**
daemon                                     **Never logged in**
bin                                        **Never logged in**
sys                                        **Never logged in**
sync                                       **Never logged in**
games                                      **Never logged in**
man                                        **Never logged in**
lp                                         **Never logged in**
mail                                       **Never logged in**
news                                       **Never logged in**
uucp                                       **Never logged in**
proxy                                      **Never logged in**
www-data                                   **Never logged in**
backup                                     **Never logged in**
list                                       **Never logged in**
irc                                        **Never logged in**
gnats                                      **Never logged in**
nobody                                     **Never logged in**
_apt                                       **Never logged in**
root@810699d1fe17:/#

컨테이너를 실행하면서 수행한 프로세스가 하나이기 때문에 사용자, 시스템 사용 흔적이 없음을 확인할 수 있다.

격리 상태를 확인하기 위해서는 호스트에서 확인하는 것이 가장 확실하다.

bash 를 실행중인 ubuntu 컨테이너가 호스트에서는 어떻게 진행되는지 살펴보기 위해 다음을 확인한다.

$ ps axfww
...
  961 ?        Ssl    0:00 /usr/bin/containerd
 2045 ?        Sl     0:00  \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/810699d1fe173ef0341a8325f81696b3da935d5aefd43454ca573b07b1235d2e -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
 2071 pts/0    Ss     0:00      \_ bash
...

컨테이너에 bash 가 실행되는 것을 확인할 수 있다.

$ mount | grep docker
overlay on /var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/SCOELRQA7BW5JOXNR4IDAUNX2U:/var/lib/docker/overlay2/l/PAIOSR5EXBVFXYJIZ2BISHONKO:/var/lib/docker/overlay2/l/OLRJYWEFJXHHANEN274OLS34DQ:/var/lib/docker/overlay2/l/4NUC7DHCQWFW3LIGNAWKWTIHBF:/var/lib/docker/overlay2/l/VAIYUGOZSB3VHLXKXDWED6ZTGZ,upperdir=/var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/diff,workdir=/var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/work)
nsfs on /run/docker/netns/871995a295a4 type nsfs (rw)

위의 명령어로 확인할 수 있는 것은 첫 구문에서 overlay 로 마운트 된 파일 시스템이 컨테이너와 연관이 있음을 알 수 있다.

또한 첫 구문의 .../merged 에서 layered image 가 병합된 것으로 유추할 수 있다. (뒷 구문의 : 이 각 레이어 연결을 위한 것임을 유추할 수 있다.)

$ sudo ls /var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/merged
bin   dev  home  lib64	mnt  proc  run	 srv  tmp  var
boot  etc  lib	 media	opt  root  sbin  sys  usr

호스트에서 마운트된 컨테이너를 위와 같이 확인하면 컨테이너에서 확인한 ls 의 모습과 같다.

ubuntu 컨테이너에 파일을 하나 만들고

root@810699d1fe17:/# touch testfile
root@810699d1fe17:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  _testfile_  usr
boot  etc  lib   media  opt  root  sbin  sys  tmp       var
root@810699d1fe17:/#

호스트에서 확인하면

$ sudo ls /var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/merged
bin   dev  home  lib64	mnt  proc  run	 srv  _testfile_	usr
boot  etc  lib	 media	opt  root  sbin  sys  tmp	var

반대로 호스트에서 생성된 파일을 삭제한 후 컨테이너에 반영이 되었는지 확인해보면 양쪽이 연관이 있음을 알 수 있다.

$ sudo rm /var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/merged/testfile
$ sudo ls /var/lib/docker/overlay2/71a98749345978590390cab34127fe227316292e7f510ab8e8e3e000cfede33e/merged
bin   dev  home  lib64	mnt  proc  run	 srv  tmp  var
boot  etc  lib	 media	opt  root  sbin  sys  usr

...

root@810699d1fe17:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

컨테이너에서 생성한 testfile 을 호스트에서 어떻게 바인드 되어 있는지 확인할 수 있다.

이를 통해 호스트가 컨테이너의 OS 역할을 수행하는 것을 알 수 있다. 즉, VM 에서 이야기 하는 Disk OS 는 호스트에 의해 처리되는 것이다.


Install Docker

Get Docker Engine

다음 공식 링크를 참조하기 바란다. (https://docs.docker.com/install/linux/docker-ce/ubuntu/)

  • Docker repository 를 사용하는 것을 권장함
  • DEB 패키지를 사용하여 수동으로 설치 및 업그레이드를 관리할 수 있음 (인터넷에 접속이 불가한 경우 유용)
  • 스크립트를 사용하여 설치할 수 있음

1. SET UP THE REPOSITORY

1-1) apt 패키지를 업데이트 한다:

sudo apt update

1-2) apt 를 통해 업데이트 할 수 있도록 패키지를 설치한다:

sudo apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common

1-3) GPG key 를 추가한다:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  • 이상이 발생하는 경우 다음을 통해 키를 확인한다.
sudo apt-key fingerprint 0EBFCD88

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

1-4) docker repository 를 설정한다:

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

2. INSTALL DOCKER ENGINE

2-1) apt 패키지를 업데이트 한다:

sudo apt update

2-2) docker engine 최신 버전을 설치한다:

sudo apt-get install docker-ce docker-ce-cli containerd.io
  • 특정 버전을 사용하는 경우 다음을 확인한다:
apt-cache madison docker-ce

  docker-ce | 5:18.09.1~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 5:18.09.0~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 18.06.1~ce~3-0~ubuntu       | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 18.06.0~ce~3-0~ubuntu       | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  ...
sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
  • docker 를 root 권한으로 실행할 수 있도록 한다:
sudo usermod -aG docker $USER

3. REMOVE DOCKER

3-1) docker engine 패키지를 제거한다:

sudo apt purge docker-ce

3-2) 모든 이미지, 컨테이너, 볼륨을 삭제한다:

  • 호스트 이미지, 컨테이너, 볼륨, 사용자 정의 구성 파일은 자동으로 제거되지 않기 때문
sudo rm -rf /var/lib/docker

Docker Commands

1. SEARCH IMAGE

Docker 는 기본적으로 Docker Hub (URL: https://hub.docker.com/) 을 통해 image 를 공유한다. 대부분의 리눅스 배포판, 오픈소스 등의 image 는 이미 Docker Hub 에서 제공한다.

docker search 명령을 사용하면 Docker Hub 의 image 를 검색할 수 있는데 랭킹을 구성해서 높은 순서대로 25 개의 리스트가 검색된다. (모든 버전이 검색되는 것은 아님)

$ docker search ubuntu
NAME                                                      DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
ubuntu                                                    Ubuntu is a Debian-based Linux operating sys…   10530               [OK]
dorowu/ubuntu-desktop-lxde-vnc                            Docker image to provide HTML5 VNC interface …   393                                     [OK]
rastasheep/ubuntu-sshd                                    Dockerized SSH service, built on top of offi…   243                                     [OK]
consol/ubuntu-xfce-vnc                                    Ubuntu container with "headless" VNC session…   210                                     [OK]
ubuntu-upstart                                            Upstart is an event-based replacement for th…   105                 [OK]
ansible/ubuntu14.04-ansible                               Ubuntu 14.04 LTS with ansible                   98                                      [OK]
neurodebian                                               NeuroDebian provides neuroscience research s…   64                  [OK]
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5      ubuntu-16-nginx-php-phpmyadmin-mysql-5          50                                      [OK]
ubuntu-debootstrap                                        debootstrap --variant=minbase --components=m…   42                  [OK]
nuagebec/ubuntu                                           Simple always updated Ubuntu docker images w…   24                                      [OK]
i386/ubuntu                                               Ubuntu is a Debian-based Linux operating sys…   19
1and1internet/ubuntu-16-apache-php-5.6                    ubuntu-16-apache-php-5.6                        14                                      [OK]
1and1internet/ubuntu-16-apache-php-7.0                    ubuntu-16-apache-php-7.0                        13                                      [OK]
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mariadb-10   ubuntu-16-nginx-php-phpmyadmin-mariadb-10       11                                      [OK]
1and1internet/ubuntu-16-nginx-php-5.6                     ubuntu-16-nginx-php-5.6                         8                                       [OK]
1and1internet/ubuntu-16-nginx-php-5.6-wordpress-4         ubuntu-16-nginx-php-5.6-wordpress-4             7                                       [OK]
1and1internet/ubuntu-16-apache-php-7.1                    ubuntu-16-apache-php-7.1                        6                                       [OK]
darksheer/ubuntu                                          Base Ubuntu Image -- Updated hourly             5                                       [OK]
1and1internet/ubuntu-16-nginx-php-7.0                     ubuntu-16-nginx-php-7.0                         4                                       [OK]
pivotaldata/ubuntu                                        A quick freshening-up of the base Ubuntu doc…   3
pivotaldata/ubuntu16.04-build                             Ubuntu 16.04 image for GPDB compilation         2
1and1internet/ubuntu-16-sshd                              ubuntu-16-sshd                                  1                                       [OK]
1and1internet/ubuntu-16-php-7.1                           ubuntu-16-php-7.1                               1                                       [OK]
pivotaldata/ubuntu-gpdb-dev                               Ubuntu images for GPDB development              1
smartentry/ubuntu                                         ubuntu with smartentry                          1                                       [OK]

대표적으로 ‘ubuntu’ 를 검색해보면 그 결과는 위와 같다. 결과에서 ‘/’ 로 나누어 지는 부분은 사용자들이 만들어 공개한 이미지이다.

Docker Hub 페이지에서 ‘ubuntu’ 를 검색할 수 있다. 검색의 결과는 다음 링크 에서 확인가능하며 ‘Docker Official Images’ 를 선택하면 세부 정보를 확인할 수 있다. 예를들어 ubuntu image Tags 탭을 보면 현재 버전정보를 확인할 수 있다.

2. PULL IMAGE

docker pull 명령을 사용하여 image 를 다운로드 받을 수 있는데 ‘검색’ 후 원하는 image Name 과 Tag 를 사용하면 된다.

‘search’ 과정에서 검색한 ‘ubuntu’ 를 예로들면 다음과 같다:

$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
5c939e3a4d10: Pull complete
c63719cdbe7a: Pull complete
19a861ea6baf: Pull complete
651c9d2d6c4f: Pull complete
Digest: sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

‘Using default tag: latest’ 구문에서 볼 수 있듯 tag 정보를 사용하지 않으면 자동적으로 최신 tag 가 적용되는 것을 확인할 수 있다.

또한 아래와 같이 다양한 구성으로 image 를 받을 수 있다:

$ docker pull ubuntu:latest

$ docker pull ubuntu:18.04

$ docker pull smartentry/ubuntu

image 이름에서 ‘smartentry/unbuntu’ 와 같이 ‘/’ 앞에 사용자를 지정하면 해당 사용자가 Docker Hub 에 push 한 image 를 다운로드 하게 된다.

공식 image 의 경우 사용자 지정을 사용하지 않는다.

3. CHECK DOCKER IMAGE LIST

docker pull 명령어로 다운로드 받은 image 가 호스트에 정상적으로 반영되었는지 확인하기 위해 docker images 명령어를 사용한다.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              ccc6e87d482b        5 weeks ago         64.2MB

$ docker images ubuntu
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              ccc6e87d482b        5 weeks ago         64.2MB

docker images <image Name> 을 사용하면 image Name 에 해당하는 정보만 출력된다. 이름은 같지만 태그가 다른 이미지도 확인할 수 있다.

4. RUN CONTAINER

호스트에 다운로드 된 image 를 이용하여 Container 를 실행시키기 위해서는 docker run 명령어를 사용한다.

$ docker run -i -t --name test ubuntu /bin/bash
root@f3ca7c49d662:/#

명령어 구성은 docker run <옵션> <image Name> <task> 형식을 사용한다. 위 예제는 ‘ubuntu’ image 를 사용하여 Container 를 생성하고 ‘/bin/bash’ 를 실행하는 의미인데 세부적인 내용은 다음과 같다:

  • -i (interactive), -t (Pseudo-tty) 옵션: ‘bash’ 쉘에 입출력을 위해 대기
  • --name 옵션: Container Name 설정 (Name 지정이 없으면 자동생성)

호스트와 격리된 Container 가 생성되었다는 의미이며 ‘bash’ 쉘에서 대기상태이기 때문에 linux 명령어들을 적용하여 동작하는지 확인한다.

root@f3ca7c49d662:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@f3ca7c49d662:/# cd home/
root@f3ca7c49d662:/home# cd ..
root@f3ca7c49d662:/# cd usr/
bin/     games/   include/ lib/     local/   sbin/    share/   src/
root@f3ca7c49d662:/# cd usr/local/
bin/     etc/     games/   include/ lib/     man/     sbin/    share/   src/

‘bash’ 쉘에 exit 를 입력하면 쉘에서 빠져나오게 되며 이 의미는 ‘ubuntu’ image 에서 ‘/bin/bash’ 실행이 종료되어 Container 가 정지 (STOP) 된다는 의미이다.

root@f3ca7c49d662:/usr/local/bin# exit
exit
$

5. CHECK CONTAINER LIST

호스트에서 만들어진 Container 목록은 docker ps 명령을 사용하여 확인할 수 있다.

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
f3ca7c49d662        ubuntu              "/bin/bash"         15 minutes ago      Exited (0) About a minute ago                       test

docker ps <option> 형식으로 구성되어 있는데 -a 옵션은 모든 Container 목록 (정지, 실행) 을 출력하는 의미이며 옵션이 없으면 실행중인 Container 만 출력한다.

위 예에서 Container 생성에 ‘–name’ 으로 지정한 Container Name 인 ‘test’ 를 확인할 수 있다.

6. CONTAINER START

정지한 Container 를 시작하기 위해 docker start 명령어를 사용한다.

$ docker start test
test

docker start <Container Name | Container ID> 형식을 사용한다.

‘start’ 명령이 정상 동작하는지 확인하기 위해 Container 목록을 출력하여 상태를 확인한다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f3ca7c49d662        ubuntu              "/bin/bash"         20 minutes ago      Up 15 seconds                           test

‘test’ 이름의 Container 가 ‘Up 15 seconds’ 임을 확인할 수 있다.

7. CONTAINER RESTART

Container 를 재실행 시키기 위해 docker restart 명령어를 사용한다.

$ docker restart test
test

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f3ca7c49d662        ubuntu              "/bin/bash"         35 minutes ago      Up 5 seconds                            test

8. CONNECTION CONTAINER

Container 가 시작된 후 Container 에 접속하기 위해 docker attach 명령어를 사용한다.

$ docker attach test
root@f3ca7c49d662:/#

docker attach <Container Name | ID> 형식을 사용하는데 주의할 점이 있다.

위 예에서는 ‘/bin/bash’ 를 실행하였기 때문에 명령어를 입력할 수 있지만 application 을 실행하는 경우라면 출력만 확인하게 된다.

쉘에서 ‘exit, ctrl+D’ 를 사용하면 Container 가 정지되며 빠져나오게 되며 ‘ctrl+P, ctrl+Q’ 를 입력하면 Container 를 정지하지 않고 빠져나오게 된다.

root@f3ca7c49d662:/# read escape sequence

9. TASK RUN

외부에서 Container 의 ‘task’ 를 실행시키기 위해 docker exec 명령어를 사용한다.

$ docker exec test echo "Hello World"
Hello World

docker exec <Container Name | ID> <task> <parameter> 형식으로 구성되는데 Container 가 실행중인 상태에서만 동작한다.

위 예에서는 ‘test’ 라는 이름의 Container 내부에 ‘echo’ 라는 task 를 실행하고 파라메터로 ‘Hello World’ 를 지정한 동작을 보여준다.

이를 사용하면 실행중인 Container 에 apt install, ‘git clone` 등의 명령으로 패키지를 설치하거나 실행할 수 있다.

$ docker exec -i -t test /bin/bash
root@f3ca7c49d662:/# apt update
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
Get:3 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [823 kB]
Get:4 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:5 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Get:6 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB]
Get:7 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB]
Get:8 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB]
Get:9 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [31.0 kB]
Get:10 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [836 kB]
Get:11 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [7348 B]
Get:12 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB]
Get:13 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [1124 kB]
Get:14 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [1350 kB]
Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [44.7 kB]
Get:16 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [11.4 kB]
Get:17 http://archive.ubuntu.com/ubuntu bionic-backports/main amd64 Packages [2496 B]
Get:18 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [4252 B]
Fetched 17.6 MB in 28s (639 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
18 packages can be upgraded. Run 'apt list --upgradable' to see them.

root@f3ca7c49d662:/# apt install git
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  ca-certificates git-man krb5-locales less libasn1-8-heimdal libbsd0 libcurl3-gnutls libedit2 liberror-perl libexpat1 libgdbm-compat4 libgdbm5 libgssapi-krb5-2
  libgssapi3-heimdal libhcrypto4-heimdal libheimbase1-heimdal libheimntlm0-heimdal libhx509-5-heimdal libk5crypto3 libkeyutils1 libkrb5-26-heimdal libkrb5-3
  libkrb5support0 libldap-2.4-2 libldap-common libnghttp2-14 libperl5.26 libpsl5 libroken18-heimdal librtmp1 libsasl2-2 libsasl2-modules libsasl2-modules-db
  libsqlite3-0 libssl1.0.0 libssl1.1 libwind0-heimdal libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxext6 libxmuu1 multiarch-support netbase openssh-client
  openssl patch perl perl-modules-5.26 publicsuffix xauth
Suggested packages:
  gettext-base git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui gitk gitweb git-cvs git-mediawiki git-svn gdbm-l10n krb5-doc krb5-user
  libsasl2-modules-gssapi-mit | libsasl2-modules-gssapi-heimdal libsasl2-modules-ldap libsasl2-modules-otp libsasl2-modules-sql keychain libpam-ssh monkeysphere
  ssh-askpass ed diffutils-doc perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl make
The following NEW packages will be installed:
  ca-certificates git git-man krb5-locales less libasn1-8-heimdal libbsd0 libcurl3-gnutls libedit2 liberror-perl libexpat1 libgdbm-compat4 libgdbm5
  libgssapi-krb5-2 libgssapi3-heimdal libhcrypto4-heimdal libheimbase1-heimdal libheimntlm0-heimdal libhx509-5-heimdal libk5crypto3 libkeyutils1
  libkrb5-26-heimdal libkrb5-3 libkrb5support0 libldap-2.4-2 libldap-common libnghttp2-14 libperl5.26 libpsl5 libroken18-heimdal librtmp1 libsasl2-2
  libsasl2-modules libsasl2-modules-db libsqlite3-0 libssl1.0.0 libssl1.1 libwind0-heimdal libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxext6 libxmuu1
  multiarch-support netbase openssh-client openssl patch perl perl-modules-5.26 publicsuffix xauth
0 upgraded, 54 newly installed, 0 to remove and 18 not upgraded.
Need to get 18.9 MB of archives.
After this operation, 103 MB of additional disk space will be used.
Do you want to continue? [Y/n]

10. STOP CONTAINER

실행중인 Container 를 정지하기 위해 docker stop 명령어를 사용한다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f3ca7c49d662        ubuntu              "/bin/bash"         About an hour ago   Up 32 minutes                           test

$ docker stop test
test

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

docker stop <Container Name | ID> 형식을 사용하며 실행중인 Container 리스트를 확인하면 비어있는 리스트를 확인할 수 있다.

11. REMOVE CONTAINER

생성된 Container 를 삭제하기 위해서 docker rm 명령어를 사용한다.

$ docker rm test
test

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS               NAMES

docker rm <Container Name | ID> 형식으로 docker ps -a 명령어로 확인하면 아무것도 없는 것을 확인할 수 있다.

12. REMOVE IMAGE

Container 의 image 삭제는 docker rmi 명령어를 사용한다.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              ccc6e87d482b        5 weeks ago         64.2MB

$ docker rmi ubuntu:latest
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110
Deleted: sha256:ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0
Deleted: sha256:d1b7fedd4314279a7c28d01177ff56bcff65300f6d41655394bf5d8b788567f6
Deleted: sha256:340bed96497252624f5e4b0f42accfe7edbb7a01047e2bb5a8142b2464008e73
Deleted: sha256:6357c335cdfcc3a120e288bbd203bf4c861a14245ce5094634ee097e5217085b
Deleted: sha256:43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

docker rmi <Image Name | ID>:<TAG> 형식으로 구성되며 docker images 명령어로 확인하면 image 가 없는 것을 확인할 수 있다.

docker rmi <Image Name> 과 같이 ‘image Name’ 만 지정하는 경우 TAG 에 상관없이 같은 이름을 모두 삭제한다.