[Ethereum] 클라우드 프라이빗 네트워크 구축

구글 클라우드 플랫폼의 기능 중 쿠버네티스 엔진으로 프라이빗 네트워크를 구축하는 실습을 진행하였습니다.

위의 사이트를 이용해 약관 및 결제정보를 입력하고 가입합니다.

좌측 메뉴의 Kubernetes Engine클러스터를 눌러 시작합니다.

구글 클라우드 SDK

구글 클라우드 SDK를 설치하고 이를 이용해 구성합니다.

설치

1
2
3
4
5
# 설치
% brew install --cask google-cloud-sdk

# macOS PATH 환경 변수 추가
% echo "source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc'" >> ~/.zprofile $ source ~/.zprofile

gcloud 버전 확인

1
2
3
4
5
6
% gcloud --version
Google Cloud SDK 412.0.0
bq 2.0.83
core 2022.12.09
gcloud-crc32c 1.0.0
gsutil 5.17

구글 클라우드 SDK 인증

1
2
% gcloud auth login
# 이후 브라우저에서 로그인

구글 클라우드 SDK 초기화

1
2
3
4
5
6
7
8
9
10
11
12
% gcloud init
Welcome! This command will take you through the configuration of gcloud.

Settings from your current configuration [default] are:
core:
account: devsawd@gmail.com
disable_usage_reporting: 'True'

Pick configuration to use:
[1] Re-initialize this configuration [default] with new settings
[2] Create a new configuration
Please enter your numeric choice: 1 #1을 선택

1을 선택하여 기본값으로 설정합니다.

계정 선택

1
2
3
4
5
6
7
Choose the account you would like to use to perform operations for this 
configuration:
[1] devsawd@gmail.com
[2] Log in with a new account
Please enter your numeric choice: 1

You are logged in as: [devsawd@gmail.com].

프로젝트 선택 및 리전 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
Pick cloud project to use: 
[1] flash-freehold-371706
[2] Enter a project ID
[3] Create a new project
Please enter numeric choice or text value (must exactly match list item): 1

Your current project has been set to: [flash-freehold-371706].

Do you want to configure a default Compute Region and Zone? (Y/n)? Y

//... 생략
Too many options [107]. Enter "list" at prompt to print choices fully.
Please enter numeric choice or text value (must exactly match list item): 34

제 클라우드 프로젝트는 flash-freehold-371706으로 자동 설정되었습니다.

아래부터는 {PROJECT_ID}로 표시하겠습니다.

만약 클라우드 프로젝트 ID를 모르는 분들은 https://cloud.google.com/ 로그인 후 우측 상단에 [콘솔]을 누르면 프로젝트 번호와 프로젝트 ID를 보실 수 있습니다.

프로젝트 ID를 확인하세요.

34 'asia-northeast1-a' 도쿄 리전을 선택합니다.

kubectl

쿠버네티스 커맨드라인 툴인 kubectl입니다.

설치

gcloud로 kubectl을 설치합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
% gcloud components install kubectl


Your current Google Cloud CLI version is: 412.0.0
Installing components from version: 412.0.0

┌─────────────────────────────────────────────┐
│ These components will be installed. │
├────────────────────────┬─────────┬──────────┤
│ Name │ Version │ Size │
├────────────────────────┼─────────┼──────────┤
│ gke-gcloud-auth-plugin │ 0.4.0 │ 7.1 MiB │
│ kubectl │ 1.23.14 │ 78.7 MiB │
│ kubectl │ 1.23.14 │ < 1 MiB │
└────────────────────────┴─────────┴──────────┘

For the latest full release notes, please visit:
https://cloud.google.com/sdk/release_notes

Do you want to continue (Y/n)? Y

kubectl 버전 확인

1
2
3
# 버전 확인
% kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.5", GitCommit:"5c99e2ac2ff9a3c549d9ca665e7bc05a3e18f07e", GitTreeState:"clean", BuildDate:"2021-12-16T08:38:33Z", GoVersion:"go1.16.12", Compiler:"gc", Platform:"darwin/arm64"}

클러스터 만들기

머신타입 e2-medium의 노드를 3개를 만듭니다.

1
2
3
4
5
6
7
% gcloud container clusters create private-net

//생략

kubeconfig entry generated for private-net.
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
private-net asia-northeast1-a 1.24.5-gke.600 35.200.60.221 e2-medium 1.24.5-gke.600 3 RUNNING

노드 확인

1
2
3
4
5
kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-private-net-default-pool-6fbfda54-4spn Ready <none> 66m v1.24.5-gke.600
gke-private-net-default-pool-6fbfda54-fcgn Ready <none> 66m v1.24.5-gke.600
gke-private-net-default-pool-6fbfda54-z8j3 Ready <none> 66m v1.24.5-gke.600

쿠버네티스를 위한 도커 컨테이너 만들기

쿠버네티스는 도커 등에서 이용하는 컨테이너를 운영하고 관리합니다.

Dockerfile 생성

private-net 디렉터리에서 Dockerfile이라는 문서를 만듭니다.

1
2
3
4
5
6
7
8
9
10
11
FROM ethereum/client-go

COPY genesis.json /var/share/ethereum/
COPY keystore /var/share/ethereum/keystore/
COPY password /var/share/ethereum/
COPY entrypoint.sh /
RUN chmod 744 /entrypoint.sh

EXPOSE 8545 8546 30303 30303/udp

ENTRYPOINT ["/entrypoint.sh"]

ethereum/client-go 이미지를 기반으로 하여 private-net 폴더 안에 있는 실행에 필요한 파일들을 지정합니다.

entrypoint.sh 생성

컨테이너를 처음 실행할 때 프라이빗 네트워크를 초기화, 실행하는 데 필요한 스크립트입니다.
private-net 디렉터리 안에 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
geth --datadir /var/share/ethereum --nodiscover --maxpeers 0 \
init /var/share/ethereum/genesis.json \
&& \
geth --datadir /var/share/ethereum --networkid 15 \
--nodiscover --maxpeers 0 --mine --miner.threads 1 \
--http --http.addr "0.0.0.0" --http.corsdomain "*" \
--http.vhosts "*" --http.api "eth,web3,personal,net,miner" \
--ipcpath /tmp/geth.ipc --ws --ws.addr "0.0.0.0" \
--ws.api "eth,web3,personal,net,miner" --ws.origins "*" \
--allow-insecure-unlock --password /var/share/ethereum/password

컨테이너 이미지 만들기

제 로컬 환경은 M1 맥북에어이기 때문에 일반적인 docker build로 이미지를 빌드하여 올리면 amd 환경에서는 정상적으로 실행되지 않습니다.

따라서 docker buildx를 이용해서 amd64arm64를 모두 빌드해서 로컬 및 클라우드에서 모두 확인해 볼겁니다.

1
2
3
4
# builder 생성 및 사용 설정
% docker buildx create --name multiarch-builder --use
# 빌드 완료 후 구글 클라우드로 이미지 푸쉬
% docker buildx build --push --platform linux/amd64,linux/arm64 --tag gcr.io/{PROJECT_ID}/private-net .

오류1

아래와 같은 오류 발생 시 도커를 실행해주세요.

1
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

오류2

push 실패시 아래의 절차를 진행 후 다시 시도합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
The push refers to repository [gcr.io/{PROJECT_ID}/private-net]
035fcda135f4: Preparing
3497c9d4f0f3: Preparing
fc68344ae935: Preparing
b04ac25474eb: Preparing
6c4d81675161: Preparing
f4d3f9e1ca46: Waiting
5d68f8622ea4: Waiting
1b577a8fb8ce: Waiting
unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication

# gcloud 로그인
% gcloud auth login
% gcloud auth configure-docker

로컬에서 컨테이너 이미지 실행

1
% docker run -it gcr.io/{PROJECT_ID}/private-net

정상적으로 실행되는지 확인 후 꺼줍니다.

노드에 컨테이너 배포

private-net.yaml 생성

private-net 디렉터리 안에 private-net.yaml을 만듭니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
apiVersion: apps/v1
kind: Deployment
metadata:
name: private-net
namespace: default
labels:
app: private-net
spec:
replicas: 1
selector:
matchLabels:
app: private-net
template:
metadata:
labels:
app: private-net
spec:
containers:
- name: private-net
image: gcr.io/{PROJECT_ID}/private-net:latest
imagePullPolicy: Always
ports:
- name: rpc
containerPort: 8545
- name: ws
containerPort: 8546
---
apiVersion: v1
kind: Service
metadata:
name: private-net
namespace: default
labels:
app: private-net
spec:
type: NodePort
ports:
- name: rpc
port: 8545
nodePort: 30045
- name: ws
port: 8546
nodePort: 30046
selector:
app: private-net

배포와 확인

1
2
3
4
5
6
7
8
9
10
11
% kubectl apply -f private-net.yaml

% kubectl get pods,deployments,service -l app=private-net
NAME READY STATUS RESTARTS AGE
pod/private-net-57bc75797b-mcz5g 1/1 Running 0 45m

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/private-net 1/1 1 1 45m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/private-net NodePort 10.28.10.115 <none> 8545:30045/TCP,8546:30046/TCP 45m

이때 pod의 READY 부분이 1/1인지, deployment의 READY가 1/1인지 꼭 확인해야합니다.

만약 0/1로 나온다면 앞의 단계에서 문제가 발생해서 배포가 정상적으로 이루어지지 않은것입니다.

방화벽 해제

30045, 30046포트의 방화벽을 해제해줍니다.

1
2
3
4
5
6
7
8
9
10
11
% gcloud compute firewall-rules create private-net-rpc --allow=tcp:30045
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/{PROJECT_ID}/global/firewalls/private-net-rpc].
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
private-net-rpc default INGRESS 1000 tcp:30045 False

% gcloud compute firewall-rules create private-net-ws --allow=tcp:30046
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/{PROJECT_ID}/global/firewalls/private-net-ws].
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
private-net-ws default INGRESS 1000 tcp:30046 False

쿠버네티스 노드의 IP 주소 확인

jq 설치

M1 맥북에서는 후자의 명령어를 이용해 설치해주세요.

1
2
3
4
5
# jq 설치
% brew install jq

# M1맥북에서 jq 설치
% arch -arm64 brew install jq

jq를 이용해 노드 외부IP 주소 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
% kubectl get nodes -o json | jq ".items[]|{name: .metadata.name, externalIP: .status.addresses[1].address}"
{
"name": "gke-private-net-default-pool-c76adc95-165n",
"externalIP": "35.243.121.19"
}
{
"name": "gke-private-net-default-pool-c76adc95-c0xr",
"externalIP": "34.84.135.176"
}
{
"name": "gke-private-net-default-pool-c76adc95-hk9d",
"externalIP": "34.146.225.74"
}

접속 확인

위의 externalIP중에 하나를 선택해 Geth로 접속할 수 있는지 확인합니다.

1
2
3
4
5
6
7
8
9
10
% geth attach http://35.243.121.19:30045
Welcome to the Geth JavaScript console!

instance: Geth/v1.11.0-unstable-f53ff0ff/linux-amd64/go1.19.4
coinbase: 0x945cd603a6754cb13c3d61d8fe240990f86f9f8a
at block: 0 (Thu Jan 01 1970 09:00:00 GMT+0900 (KST))
modules: eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 web3:1.0

To exit, press ctrl-d or type exit
>

위와 같이 ip주소와 port만 알면 Geth에 접속할 수 있게 되었습니다.

사용하지 않을때는 노드들을 꼭 중지시켜주세요.