기본 환경
Host
VMware® Workstation 14 Player 14.0.0 build-6661328
OS
Ubuntu 16.04.6 LTS
Application
- Docker : 19.03.5, build 633a0ea838
- docker-compose : 1.11.2, build dfed245
- git : 2.7.4
- go: go1.14 lunux/amd64
- node: v8.17.0
- npm: 6.13.4
IPFS Network
IPFS 네트워크에는 공용(public) 및 개인용(Private)의 두 가지 유형이 있습니다. 공용 IPFS 네트워크의 모든 파일은 모든 사람이 액세스 할 수 있습니다. 대부분의 비즈니스 응용 프로그램, 특히 엔터프라이즈 솔루션은 데이터에 대한 완전한 제어가 필요하기 때문에 네트워크를 공개적으로 사용할 수 있도록하는 것은 옵션이 아닙니다. IPFS 개인 정보 보호 기능이 특정 엔터티의 네트워크를 닫는 데 도움이 될 수 있습니다.
이 IPFS 튜토리얼에서는 도커(Docker) 기반으로 Private IPFS 네트워크를 만들고 Private IPFS 네트워크 위에 데이터 복제를 위한 IPFS- cluster 를 설정하는 프로세스를 살펴봅니다.
IPFS: 분산 파일 시스템에서 하이퍼 미디어를 저장하고 공유하는 콘텐츠 주소 지정이 가능한 P2P 방식을 생성하도록 설계된 프로토콜 및 네트워크입니다.
사설 IPFS: IPFS가 공유 비밀 키(secret key)를 가진 다른 피어에만 연결할 수 있도록 합니다. IPFS 사설 네트워크를 사용하면 각 노드가 연결할 다른 노드를 지정합니다. 해당 네트워크의 노드는 해당 네트워크 외부 노드의 통신에 응답하지 않습니다.
IPFS-Cluster: IPFS-Cluster는 독립적인 애플리케이션이며 IPFS 데몬 클러스터에서 핀을 할당, 복제 및 추적하는 CLI 클라이언트입니다. IPFS-Cluster 는 리더 기반 합의 알고리즘 Raft 를 사용하여 핀셋의 스토리지를 조정하고 참여 노드에 데이터 세트를 배포합니다.
사설 네트워크는 핵심 IPFS 기능 내에서 구현되는 기본 기능 이고 IPFS-Cluster 는 별도의 앱 이라는 점은 주목할 가치가 있습니다. IPFS 및 IPFS-Cluster 애플리케이션은 서로 다른 패키지로 설치되고 별도의 프로세스로 실행되며 API 엔드 포인트 및 포트는 물론 서로 다른 피어 ID를 갖습니다. IPFS-Cluster 데몬은 IPFS 데몬에 의존하며 나중에 시작해야합니다.
기본적으로 IPFS 및 IPFS-Cluster는 다음 포트를 사용합니다.
IPFS
PORT | 설명 |
4001 | 다른 노드와 통신 |
5001 | API 서버 |
8080 | 게이트웨이 서버 |
IPFS-CLUSTER
PORT | 설명 |
9094 | HTTP API 엔드 포인트 |
9095 | IPFS 프록시 엔드 포인트 |
9096 | 클러스터 노드 간 통신에 사용되는 클러스터들 |
두 개의 VM이 있다고 가정합니다.
도커의 볼륨을 다음과 같이 사용할 것입니다. 미리 디렉터리를 생성 후 폴더 권한 부여를 해주세요.
/data/ipfs: ipfs 에서 필요한 데이터 볼륨
/data/ipfs-staging: ipfs 업/다운로드할 파일 경로
/data/ipfs-cluster: ipfs-cluster 에서 필요한 데이터 볼륨
1단계: IPFS Docker 로 설치하기
최신 버전의 go-ipfs 도커 이미지로 설치합니다.
docker run \
-d \
--restart always \
--name ipfs-node \
-v /data/ipfs:/data/ipfs \
-v /data/ipfs-staging:/staging \
-p 8080:8080 \
-p 4001:4001 \
-p 5001:5001 \
--network="ipfs" \
ipfs/go-ipfs:latest
NOTE: permission denide 에러가 난다면 도커 볼륨에 권한이 없어서 나는 오류일 것입니다. 폴더에 권한 부여를 해주세요. 예시) `sudo mkdir /data/ipfs && sudo chown -R hyper:hyper /data/ipfs`
docker container logs ipfs-node -f
다음과 같은 로그가 출력 됬다면 성공적으로 실행된 것입니다.
다음을 두 노드 에 실행시켜주세요.
2단계: Private 네트워크 생성 준비
모든 노트에 IPFS 를 설치했으면 다음 명령어를 실행하여 secret key 를 생성하여 네트워크 피어에게 이 비밀키를 공유하는 피어와 통신할 수 있도록 하겠습니다.
이 명령은 하나의 노드에서만 실행할 것입니다. 하나의 노드에서 생성한 다음 나머지 노드에 복사할 것입니다.
od -vN 32 -An -tx1 /dev/urandom | tr -d ' \n' && echo ""
출력한 값을 텍스트 에디터에 복사해주세요.
다음 명령어로 각각 클러스터 노드의 ID와 Private key 를 생성해 줄 것입니다.
# Key 생성
go get github.com/whyrusleeping/ipfs-key
ipfs-key | base64 | tr -d ' \n' && echo ""
NOTE: go get 이 정상적으로 동작하지 않는다면 go 버전(1.14)을 잘 확인해주세요.
다음과 같이 ID와 Private key 를 한 세트로 노드 갯수만큼(노드 2대를 사용한다면 2번) 실행시킨 다음 텍스트 에디터에 복사해주세요.
네트워크 생성에 필요한 값을 모두 출력했으니, 적용을 해보겠습니다.
/data/ipfs-cluster 에서 service.json 이라는 제목의 파일을 하나 생성해주고 내용은 다음과 같게 노드별로 채워넣어 주세요.
cd /data/ipfs-cluster
vi service.json
다음 양식에 맞춰서 노드별로 생성해주세요.
{
"cluster": {
"id": 노드별 ID,
"peername": 노드 이름,
"private_key": 노드 프라이빗 키,
"secret": 노드 간 통신을 위한 비밀 키,
"leave_on_shutdown": false,
"listen_multiaddress": "/ip4/0.0.0.0/tcp/9096",
"state_sync_interval": "10m0s",
"ipfs_sync_interval": "2m10s",
"replication_factor_min": -1,
"replication_factor_max": -1,
"monitor_ping_interval": "15s",
"peer_watch_interval": "5s",
"disable_repinning": false
},
"consensus": {
"raft": {
"init_peerset": [
노드 ID 들(자신포함),
],
"wait_for_leader_timeout": "2m",
"network_timeout": "20s",
"commit_retries": 1,
"commit_retry_delay": "200ms",
"backups_rotate": 6,
"heartbeat_timeout": "5s",
"election_timeout": "5s",
"commit_timeout": "500ms",
"max_append_entries": 64,
"trailing_logs": 10240,
"snapshot_interval": "2m0s",
"snapshot_threshold": 8192,
"leader_lease_timeout": "1s"
}
},
"api": {
"ipfsproxy": {
"node_multiaddress": "/dns4/ipfs-node/tcp/5001",
"listen_multiaddress": "/ip4/0.0.0.0/tcp/9095",
"read_timeout": "0s",
"read_header_timeout": "5s",
"write_timeout": "0s",
"idle_timeout": "1m0s"
},
"restapi": {
"http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094",
"read_timeout": "0s",
"read_header_timeout": "5s",
"write_timeout": "0s",
"idle_timeout": "2m0s",
"basic_auth_credentials": null,
"headers": {},
"cors_allowed_origins": ["*"],
"cors_allowed_methods": ["GET"],
"cors_allowed_headers": [],
"cors_exposed_headers": ["Content-Type", "X-Stream-Output", "X-Chunked-Output", "X-Content-Length"],
"cors_allow_credentials": true,
"cors_max_age": "0s"
}
},
"ipfs_connector": {
"ipfshttp": {
"node_multiaddress": "/dns4/ipfs-node/tcp/5001",
"connect_swarms_delay": "30s",
"pin_method": "refs",
"ipfs_request_timeout": "5m0s",
"pin_timeout": "24h0m0s",
"unpin_timeout": "3h0m0s"
}
},
"pin_tracker": {
"maptracker": { "max_pin_queue_size": 50000, "concurrent_pins": 10 },
"stateless": { "max_pin_queue_size": 50000, "concurrent_pins": 10 }
},
"monitor": {
"monbasic": { "check_interval": "15s" },
"pubsubmon": { "check_interval": "15s" }
},
"informer": {
"disk": { "metric_ttl": "30s", "metric_type": "freespace" },
"numpin": { "metric_ttl": "10s" }
}
}
예시
{
"cluster": {
"id": "QmPjp4tUXFaiQw5PNj5Cwfew1VufsytrzxHDDQCMgxeJt46BU",
"peername": "NODE01",
"private_key": "CAASqAkwggSkAgEAAoIBAQC6MsmUewdIgqs8M6sPwLgQnw3hDvn3ewecVoba/qB5qADUPEDL27/OvvNSyr3gyMchKN++tkfh8J+XOyzAf4wP99Lqy+Pk9ZpRSuqpmoId1RoPaypbFl4VVBnPNPDN17M4CRAJ5n10qGVLMxeAtaiOzl7ZI+I5Hd7i4lhcBgUwzWH/HLas1ClZwrQmqG8QyIAz1y8EBUd/oDvp5K8X0jk8DygOOXvxI/96rWvuSn++CoG0TqTy89i8BbneoJoUFB6Gic7IgLQnESZeOkPpncqjkYGewLNC7cSMQ0rFj6KJubIRQJSg6KbBabFDxXvIbRkEh5H62DjlctJdg/PSqu/NVXCJbAgMBAAECggEAUKGFoYAFJ1jJBjV2MBUlFOVVOC86BmgNF1naMdT9JRTCvSSTxlpjUS2jQzlDnsAyTluT20/7uF1M7cIFDIhaAP7ID8rIGDs1Z1PE1QhAORLZz58Z4gP1Sb70GfD+FQUWfUyBr6VfscVOmtwHsdHU4iygkFpL58M3GzO+p81/J+TlnExAUbSoFzO/BvH59E3rPHSW8K0pL5W0cHYQFesGoCE+puQ5nd8w22FMYBZbWvTZPgNibdnCgw9GHqeN2iUANkiATcklfHFXbkuXkwW2dqCOlLGTEtnCLHdS/Mn+8Do90LC5YMlV3j4fAi/rzD5n03Tb4P2PLXEmcUci2+ZrYQKBgQDQHxINmLDaIC+cMZRnTjG8bywfrG7+incufycjyenEfIb9g/eWphjUx+9uhLxD9++Vlddj/g0pkh3IGQqaTpgOZBB8tBsQMASVJ7VwbjKP7TACDpqPrLD/UVaksrywD3iRcuToBgweHtXREdgmS7MxJBaKyL0VStFkLhz4LVcAFwKBgQDlCJpSdbnHcbaOBFxxrSjMJ1jZHi5rBXuniBIehoWILc7p4Ilpz2rKge3hkfIzj2bFeMSDMwrZkhpoSvDBmjEPVkhLe2dT+X54FkECo+IOyIRRyPHIkmGD1O3cNlHf7E3tmchj3UgSbL/IF7Eps20Nwsepwy9TObUuZQufOo32XQKBgQCilTMoNfkqXWx0C3NQhJBsETkaAT2wUYErbJ+p4KljGpjl4TsAj/7j8tDDuKPOQRkD9UuPTL8Bk6j6UT2sL+uvilIq6RQfQDPERYIDM8MCFpujb78ksBaRTfxuq0amD1/z2Bqke1zqBtKoAdWmjQqOQA/wGUNFJ+6N4Uw2QE0vvwKBgQCCVe30RRhu3lBD60lsS10vKKkQDXPe5WTkBrRA+M6em2rnfybTtvyPt3bW6gYJv259q+cwvmhLPjCW7yapFgUbND+57MT1bcLBtfBS/04SmZtrK04klOC3dAHUUnkvU7tZHi2CXxe3nHla9diU4Y2KyjBzdCbHVsy7VTdS6rCE5QKBgD/AQlhq2xDDi++w40BJ10kyVfjMpPX67poOfCQe0h639RXTDX4U4AKJRbfCpJ4CZOYpNrUEn8ykV6ZgXaXAwk/3hkIIUiKSuTsbmvU9Z+/urhk3gBVEOY8ZO2phxzYkkg2oStSxjP7oJNxbmQ+2tL7m/JvZMTtdT9VegUeB1lmT",
"secret": "636c1291342c641ebe5d6a3c3e6cc064f30023f0146af04877fd3443a4d85dea9952bcae",
"leave_on_shutdown": false,
"listen_multiaddress": "/ip4/0.0.0.0/tcp/9096",
"state_sync_interval": "10m0s",
"ipfs_sync_interval": "2m10s",
"replication_factor_min": -1,
"replication_factor_max": -1,
"monitor_ping_interval": "15s",
"peer_watch_interval": "5s",
"disable_repinning": false
},
"consensus": {
"raft": {
"init_peerset": [
"QmPjp4tUXFaiQw5PNj5Cwfew1VufsytrzxHDDQCMgxeJt46BU",
"QmUUhF6BaKhrhq2RMt6xdfstDsLp2Zy67Pto3Hq1HeyVWE8fe",
],
"wait_for_leader_timeout": "2m",
"network_timeout": "20s",
"commit_retries": 1,
"commit_retry_delay": "200ms",
"backups_rotate": 6,
"heartbeat_timeout": "5s",
"election_timeout": "5s",
"commit_timeout": "500ms",
"max_append_entries": 64,
"trailing_logs": 10240,
"snapshot_interval": "2m0s",
"snapshot_threshold": 8192,
"leader_lease_timeout": "1s"
}
},
"api": {
"ipfsproxy": {
"node_multiaddress": "/dns4/ipfs-node/tcp/5001",
"listen_multiaddress": "/ip4/0.0.0.0/tcp/9095",
"read_timeout": "0s",
"read_header_timeout": "5s",
"write_timeout": "0s",
"idle_timeout": "1m0s"
},
"restapi": {
"http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094",
"read_timeout": "0s",
"read_header_timeout": "5s",
"write_timeout": "0s",
"idle_timeout": "2m0s",
"basic_auth_credentials": null,
"headers": {},
"cors_allowed_origins": ["*"],
"cors_allowed_methods": ["GET"],
"cors_allowed_headers": [],
"cors_exposed_headers": ["Content-Type", "X-Stream-Output", "X-Chunked-Output", "X-Content-Length"],
"cors_allow_credentials": true,
"cors_max_age": "0s"
}
},
"ipfs_connector": {
"ipfshttp": {
"node_multiaddress": "/dns4/ipfs-node/tcp/5001",
"connect_swarms_delay": "30s",
"pin_method": "refs",
"ipfs_request_timeout": "5m0s",
"pin_timeout": "24h0m0s",
"unpin_timeout": "3h0m0s"
}
},
"pin_tracker": {
"maptracker": { "max_pin_queue_size": 50000, "concurrent_pins": 10 },
"stateless": { "max_pin_queue_size": 50000, "concurrent_pins": 10 }
},
"monitor": {
"monbasic": { "check_interval": "15s" },
"pubsubmon": { "check_interval": "15s" }
},
"informer": {
"disk": { "metric_ttl": "30s", "metric_type": "freespace" },
"numpin": { "metric_ttl": "10s" }
}
}
또 작성할 파일이 있습니다. IP 로 피어를 찾기 위한 peerstore 파일을 방금 생성했던 service.json 의 위치에 peerstore 라는 제목으로 생성해주세요.
/ip4/노드1에 해당하는 IP/tcp/9096/ipfs/노드1에 해당하는 ID
/ip4/노드2에 해당하는 IP/tcp/9096/ipfs/노드2에 해당하는 ID
예시
# 노드1 IP 220.0.0.1
# 노드2 IP 220.0.0.2
/ip4/220.0.0.1/tcp/9096/ipfs/QmPjp4tUXFaiQw5PNj5Cwfew1VufsytrzxHDDQCMgxeJt46BU
/ip4/220.0.0.2/tcp/9096/ipfs/QmUUhF6BaKhrhq2RMt6xdfstDsLp2Zy67Pto3Hq1HeyVWE8fe
이제 준비는 끝났습니다. ipfs-cluster를 실행 시켜보겠습니다.
3단계: ipfs-cluster 실행하기
ipfs-cluster 최신버전의 도커 이미지로 실행시켜줍니다.
docker run \
-d \
--restart=always \
--name=ipfs-cluster \
-v /data/ipfs-cluster:/data/ipfs-cluster \
-v /data/ipfs:/data/ipfs \
-p "9094:9094" \
-p "9096:9096" \
--network="ipfs" \
ipfs/ipfs-cluster:latest
실행 후 `docker container logs ipfs-cluster -f` 명령러로 로그를 확인해보세요. 다음과 같은 로그가 뜨면 성공적으로 실행 된 것입니다.
노드 간에 연결이 잘됬는지 확인해보시려면 `docker container exec ipfs-cluster ipfs-cluster-ctl peers ls` 명령어로 확인해보세요.
참고
labs.eleks.com/2019/03/ipfs-network-data-replication.html
'기타' 카테고리의 다른 글
Postman 환경 변수( Environments Variables ) 사용하는 방법 (1) | 2021.04.28 |
---|---|
GitLab 과 Slack 연동 (0) | 2019.12.18 |
GitLab Runner 를 사용하여 GitLab CI 구성하기 (1) | 2019.12.12 |
GitLab CE 설치하기 (0) | 2019.12.12 |
Docker Local Registry 구축 (0) | 2019.12.11 |