기본 콘텐츠로 건너뛰기

[Kubernetes] kubeadm 으로 ContainerD 기반 K8S Cluster를 CentOS 8 설치하기 (Docker 사용하지 않음)

Docker를 사용하지 않고 Containerd 기반의 Kubernetes Cluster를 CentOS 8 에 kubeadm으로 설치하기

CentOS 8 버전부터 도커 Docker 는 레드햇의 도구인 podman, buildah 로 대체된 상태로 기본 패키지 저장소에서 제거되었고, API를 사용해서 처리되는 것이기 때문에 특정 툴에 한정될 필요가 없다.

현재 제공되고 있는 컨테이너 런타임Container Runtime 은 다음과 같다.

이 문서는 containerd를 사용해서 클러스터를 구성한다.

  • 1개의 마스터 노드와 3개의 워커 노드 모두 CentOS 8 설치
  • 각 노드는 2G RAM, 2 CPU 를 최소 사양으로 한다.
  • 모든 노드는 저장소에서 쿠버네티스 Kubernetes 및 기타 필수 패키지를 설치할 수 있도록 인터넷에 연결이 가능해야 하고, dnf 패키지 관리자를 사용할 수 있으며 원격으로 패키지를 가져올 수 있는지 검증되어야 한다.

설치환경 요약

쿠버네티스의 최소 요구 사항은 2G RAM, 2 CPU 를 기준으로 한다.

  • Master
    • CentOS 8.2.2004
    • monitor.master
    • centos
  • Worker
    • CentOS 8.2.2004
    • monitor.worker1, 2, 3
    • centos
  • CNI : Calico

CentOS 의 버전을 확인하는 방법은 아래와 같다.

$ cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core) 

$ cat /etc/*release*
CentOS Linux release 8.2.2004 (Core) 
Derived from Red Hat Enterprise Linux 8.2 (Source)
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

CentOS Linux release 8.2.2004 (Core) 
CentOS Linux release 8.2.2004 (Core) 
cpe:/o:centos:centos:8

CentOS 8.2의 경우 일반 계정 생성 후에 sudo 권한을 줄 경우는 아래의 명령을 사용한다.

$ usermode -aG wheel <user>

CentOS 8.2에는 wheel 이라는 특별한 그룹이 존재하는데 sudo 설정에는 이 그룹에 한해 sudo 권한을 부여하고 있기 때문에 이 그룹에 사용자를 포함시키면 된다.

공통 설정

마스터와 워커 노드 모두 Static IP를 가지고 있어야 하며, 일반 계정이 존재해야 하며 sudo 권한을 가져야 한다.

  • 관리자 권한으로 설정

    sudo -s
    
  • 패키지 관리자 갱신

    dnf -y upgrade
    
  • Hosts 정보 설정

    # 각 노드에서 각자에 맞도록 호스트 명 설정
    hostnamectl set-hostname <host name>
    
    # /etc/hosts 에 각 구성 노드들의 IP와 HostName 설정
    vi /etc/hosts
    ...
    <node ip>	<hostname>
    <node ip>	<hostname>
    ...
    
  • 방화벽 설정

    방화벽은 쿠버네티스에서 제시하는 포트들을 열어주면 사용이 가능하지만 실제 사용할 때는 쿠버네티스 공식문서에 제시되지 않은 포트들도 존재하고, 이상 동작하는 상황들도 발생하기 때문에 일반적인 테스트를 위한 실행기준으로는 방화벽을 끄고 운영하는 것을 권장한다. (당연히 프로덕션 환경이라면 필요한 포트들을 방화벽에 등록하고 정상적으로 사용해야 한다)

    CentOS 8에는 기본적인 방화벽이 설치되어 있기 않기 때문에 설치를 수행한다.

    # 방화벽 설치
    dnf -y install firewalld
    
    # 활성화
    systemctl enable firewalld
    systemctl start firewalld
    
    # 방화벽에 IP Masquerade 활성화
    firewall-cmd --add-masquerade --permanent
    firewall-cmd --reload
    
    # 상태 확인
    firewall-cmd --state
    firewall-cmd --list-all
    
    # 방화벽 끄기
    systemctl stop firewalld
    systemctl disable firewalld
    

    정상적인 방화벽 설정

    • 방화벽 규칙 설정

      # 공통으로 설정할 경우
      $ sudo firewall-cmd --permanent --add-port=22/tcp		# SSH
      $ sudo firewall-cmd --permanent --add-port=80/tcp		# Web
      $ sudo firewall-cmd --permanent --add-port=443/tcp		# API Requests and End-User, used by Workers
      $ sudo firewall-cmd --permanent --add-port=2376/tcp		# Docker daemon TLS, used by all
      $ sudo firewall-cmd --permanent --add-port=2379-2380/tcp	# ETCD Server client API, used by kueb-apiserver, etcd
      $ sudo firewall-cmd --permanent --add-port=6443/tcp		# Kubernetes API Server, used by all
      $ sudo firewall-cmd --permanent --add-port=8285/udp		# Flannel overlay network (UDP Backend), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=8472/udp		# Flannel overlay network (VxLan), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=9099/tcp		# Liveness/Readiness kubelet, API, used by Master, Worker
      $ sudo firewall-cmd --permanent --add-port=10250/tcp		# kubelet API, used by self and control plane
      $ sudo firewall-cmd --permanent --add-port=10251/tcp		# kube-scheduler, used by self
      $ sudo firewall-cmd --permanent --add-port=10252/tcp		# kube-controller-manager, used by self
      $ sudo firewall-cmd --permanent --add-port=10254/tcp		# Ingress
      $ sudo firewall-cmd --permanent --add-port=10255/tcp		# Heapster, used by Worker
      $ sudo firewall-cmd --permanent --add-port=30000-32767/tcp	# NodePort services, used by all
      $ sudo firewall-cmd --permanent --add-port=30000-32767/udp	# NodePort services, used by all
      
      # 역할별 - ETCD 운영용 노드인 경우
      $ sudo firewall-cmd --permanent --add-port=2376/tcp		# Docker daemon TLS, used by all
      $ sudo firewall-cmd --permanent --add-port=2379-2380/tcp	# ETCD Server client API, used by kueb-apiserver, etcd
      $ sudo firewall-cmd --permanent --add-port=8472/udp		# Flannel overlay network (VxLan), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=9099/tcp		# Liveness/Readiness kubelet, API, used by Master, Worker
      $ sudo firewall-cmd --permanent --add-port=10250/tcp		# kubelet API, used by self and control plane
      
      # 역할별 - 마스터 Control Plane 노드인 경우
      $ sudo firewall-cmd --permanent --add-port=80/tcp		# Web
      $ sudo firewall-cmd --permanent --add-port=443/tcp		# API Requests and End-User, used by Workers
      $ sudo firewall-cmd --permanent --add-port=2376/tcp		# Docker daemon TLS, used by all
      $ sudo firewall-cmd --permanent --add-port=6443/tcp		# Kubernetes API Server, used by all
      $ sudo firewall-cmd --permanent --add-port=8285/udp		# Flannel overlay network (UDP Backend), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=8472/udp		# Flannel overlay network (VxLan), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=9099/tcp		# Liveness/Readiness kubelet, API, used by Master, Worker
      $ sudo firewall-cmd --permanent --add-port=10250/tcp		# kubelet API, used by self and control plane
      $ sudo firewall-cmd --permanent --add-port=10254/tcp		# Ingress
      $ sudo firewall-cmd --permanent --add-port=30000-32767/tcp	# NodePort services, used by all
      $ sudo firewall-cmd --permanent --add-port=30000-32767/udp	# NodePort services, used by all
      
      # 역할별 - 워커 노드인 경우
      $ sudo firewall-cmd --permanent --add-port=22/tcp		# SSH
      $ sudo firewall-cmd --permanent --add-port=80/tcp		# Web
      $ sudo firewall-cmd --permanent --add-port=443/tcp		# API Requests and End-User, used by Workers
      $ sudo firewall-cmd --permanent --add-port=2376/tcp		# Docker daemon TLS, used by all
      $ sudo firewall-cmd --permanent --add-port=8472/udp		# Flannel overlay network (VxLan), used by Master, Worker (if use Flannel)
      $ sudo firewall-cmd --permanent --add-port=9099/tcp		# Liveness/Readiness kubelet, API, used by Master, Worker
      $ sudo firewall-cmd --permanent --add-port=10250/tcp		# kubelet API, used by self and control plane
      $ sudo firewall-cmd --permanent --add-port=10254/tcp		# Ingress
      $ sudo firewall-cmd --permanent --add-port=30000-32767/tcp	# NodePort services, used by all
      $ sudo firewall-cmd --permanent --add-port=30000-32767/udp	# NodePort services, used by all
      
      # Calico Pod Network (마스터, 워커)
      $ sudo firewall-cmd --permanent --zone=public --add-port=179/tcp	# Calico Networking (BGP), used by all (if use calico)
      
      $ sudo firewall-cmd --reload
      
  • Container Runtime 설치

    CRI Container Runetime Interface 런타임으로 사용할 containerd 를 설치한다.

    • 사전 설정

      cat > /etc/modules-load.d/containerd.conf <<EOF
      overlay
      br_netfilter
      EOF
      
      modprobe overlay
      modprobe br_netfilter
      
      # Setup required sysctl params, these persist across reboots.
      cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
      net.bridge.bridge-nf-call-iptables  = 1
      net.ipv4.ip_forward                 = 1
      net.bridge.bridge-nf-call-ip6tables = 1
      EOF
      
      sysctl --system
      
    • containerd 설치

      # Install required packages
      dnf install -y yum-utils device-mapper-persistent-data lvm2 iproute-tc
      
      # Add docker repository
      dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
      
      # dnf update and Install containerd
      dnf update -y && dnf install -y containerd.io
      
      # Configure containerd
      mkdir -p /etc/containerd
      containerd config default > /etc/containerd/config.toml
      
      # Restart containerd
      systemctl restart containerd
      
      # Enable containerd on boot
      systemctl enable containerd
      
  • Kubernetes 설치 (kubeadm, kubelet, kubectl)

    CentOS 8에 기본적으로 쿠버네티스 리포지토리가 설치되어 있지 않기 때문에 수동으로 추가해야 한다. kubeadm 은 단일 쿠버네티스 컨트롤 플레인을 생성 및 활성화하고, 업그레이드/다운그레이드 및 부트스트랩 토큰 관리와 같은 다른 클러스터 수명주기 기능도 제공한다.

    • 사전설정

      # Kubernetes Repository 추가
      cat <<EOF > /etc/yum.repos.d/kubernetes.repo
      [kubernetes]
      name=Kubernetes
      baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
      enabled=1
      gpgcheck=1
      repo_gpgcheck=1
      gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
      EOF
      
    • 설치

      # Install Kubernetes (kubeadm, kubelet and kubectl) - 특정 버전을 지정할 수 있다.
      dnf install -y kubeadm kubelet kubectl
      
    • 서비스 활성화

      # Enable kubelet service on boot
      systemctl enable kubelet
      
      # Configure kubelet
      echo 'KUBELET_EXTRA_ARGS="--fail-swap-on=false"' > /etc/sysconfig/kubelet
      
      # Start kubelet service
      systemctl start kubelet
      

마스터 노드 설정

쿠버네티스는 통신 및 액세스를 위해 다양한 포트를 사용하기 때문에 방화벽 Firewall 에 제한되지 않고 쿠버네티스에 액세스할 수 있는 상태여야 한다. 아래의 방화벽 규칙을 참고하면 된다.

Protocol Direction Port Range Purpose Used By
TCP inbound 6443 k8s API Server all
TCP inbound 2379 - 2380 ETCD server client API kube-apiserver, etcd
TCP inbound 10250 kubelet API self, control plane
TCP inbound 10251 kube-scheduler self
TCP inbound 10252 kube-controller-manager self
  • kubeadm Images Pull

    kubeadm config images pull
    
  • Create Control Plane with kubeadm

    kubeadm init --pod-network-cidr=10.15.0.0/16 --apiserver-cert-extra-sans=<master node ip>
    

    --apiserver-cert-extra-sans 는 외부에서 접근할 수 있는 IP를 지정해서 내부와 외부에서 모두 API Server로 접근할 수 있도록 지정하고 인증서에 관련된 IP 정보를 포함시킨키는 것이다.

    정상적으로 실행되면 아래와 같이 워커 노드들을 클러스터에 참여시킬 수 있는 구문이 출력된다. 이 명령을 복사해 놓고 이후 워커 노드 작업에서 사용하면 된다.

    kubeadm join xxx.xxx.xxx.xxx:6443 --token ur9jpx... \        
          --discovery-token-ca-cert-hash sha256:48e4d3cca... 
    
  • kube-api 통신을 위한 환경 설정

    쿠버네티스 마스터 명령은 모두 일반 계정으로 처리된다. 따라서 일반 계정이 kube-api 와 통신을 위해서는 아래와 같이 처리해 준다.

    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
  • Pod Network 구성

    쿠버네티스 클러스터를 구성할 때 --pod-network-cidr 옵션으로 지정한 CNI Container Network Interface 로 어떤 것을 사용할지에 따라 달라진다. 여기서는 Calico를 사용하도록 한다. 다른 CNI 들을 Installing a pod network add-on 을 참고하도록 한다.

    Calico는 쿠버네티스가 운영되는 환경에 따라 설치 과정에 차이가 있고, 같은 환경이라도 노드의 수에 따라서 설치하는 것도 다를 수 있다. 따라서 매뉴얼을 확인하고 작업할 것을 권장한다.

    여기서는 On-Premise 환경이고 노드가 50개 미만이므로 아주 간단하게 적용하도록 한다.

    kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
    

    설치된 Calico 는 워커 노드가 클러스터에 참여하면 설치되어 동작하게 된다.

워커 노드 설정

마스터 노드에 Control Plane이 설치되었으므로 이제 구성된 쿠버네티스 클러스터에 참여할 워커 노드들을 구성하면 된다.

  • Kubernetes Cluster 참여

    기본적으로 마스터 노드에 쿠버네티스 클러스터를 구성하는 작업을 통해서 발행된 토큰은 24시간 존재하도록 되어 있기 때문에 나중에 워커 노드를 추가할 경우는 토큰이 없는 상태가 발생하므로 새롭게 토큰을 생성해서 참여하면 된다.

    kubeadm token create --print-join-command
    

    위의 쿠버네티스 클러스터를 구성할 때 출력된 명령을 사용하거나 토큰이 만료된 상태라면 바로 위의 신규 토큰 생성 방법을 통해서 아래와 같이 클러스터에 참여하면 된다.

    kubeadm join 10.0.1.186:6443 --token tofo13.... --discovery-token-ca-cert-hash sha256:e39c05bb474f8e6726ef...
    

Dashboard 설치

기본으로 설치하면 Dashboard에 접근하기 위해서는 kubectl proxy 명령을 사용하고 http://localhost:8001/... 로 접근해야 한다. 그러나 실제로는 외부에서도 대시보드를 접근해서 확인하는 경우가 많기 때문에 NodePort 방식을 활용하도록 한다.

# wget이 없는 경우는 설치
dnf install -y wget

# Dashboard Manifest 파일 다운로드 (현재 버전 v2.2.0)
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml

vi recommended.yaml
...  
  ports:  
  - nodePort: 32444     # 이 부분 추가 (생략하면 Kubernetes에서 임의로 지정하므로 중복되지 않는 값으로 설정)    
    port: 443    
    targetPort: 8443  
  selector:    
    k8s-app: kubernetes-dashboard  
  type: NodePort	# 이 부분 추가
...
  
# 직접 설치 
kubectl apply -f recommended.yaml

# 설치 검증
kubectl get services --all-namespaces # 또는 kubectl get services -n kubernetes-dashboard

최근 버전에서는 기존의 kube-system 네임스페이스에서 kubernetes-dashboard 네임스페이스로 이전되었으며, dashboard와 scraper 파드가 설치된다.

실제 Dashboard를 사용하기 위해서는 사용자 정보와 클러스터 역할 및 바인딩 정보를 구성해야 한다. (파일로 구성해도 되고 직접 kubectl 명령으로 생성해도 된다)

# 서비스 계정 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:  
  name: admin-user  
  namespace: kubernetes-dashboard
EOF
  
# 클러스터 역할 바인딩 생성
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:  
  name: admin-user
roleRef:  
  apiGroup: rbac.authorization.k8s.io  
  kind: ClusterRole  
  name: cluster-admin
subjects:
- kind: ServiceAccount  
  name: admin-user  
  namespace: kubernetes-dashboard
EOF

실제 Dashboard에 접속하기 위해서는 Bearer Token을 확인해야 한다.

kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"

결과로 추출된 Bearer Token을 https://<cluster mastaer or worker node ip>:32444 로 접근해서 Token 입력에 넣고 연결하면 대시보드를 확인할 수 있다.

Helm 3 설치

Helm은 쿠버네티스에서 동작하는 많은 애플리케이션들을 손쉽게 설치하도록 지원하는 프로그램으로 Ubuntu의 apt 나 CentOS 의 dnf 와 같은 패키지 관리자와 유사하다고 이해하면 된다.

기존 Helm 2 에서는 Tiler라는 Helm 서버가 필요했지만 Helm 3 에서는 좀 더 단순한 구조로 변경이 되었기 때문에 쉽게 설치 및 사용할 수 있다.

설치는 kubectl이 지원되는 모든 노드에서 사용 가능하다.

# 설치 스크립트를 다운로드해서 설치
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh
  
# 설치 확인 (현재 버전 v3.5.4)
helm version
  
# 설치는 /usr/local/bin 경로에 처리되므로 PATH 환경변수에 해당 경로가 설정되어 있어야 한다.
export PATH=/usr/local/bin:$PATH

기본 저장소를 가지고 있지 않기 때문에 설치를 진행할 수 없으므로 기본 저장소를 추가해 준다.

# Repo 검증
helm search repo
  
# 기본 Repo 추가 (기존의 https://kubernetes-charts.storage.googleapis.com/ 는 더이상 지원되지 않는다)
helm repo add stable https://charts.helm.sh/stable
  
# Repo 챠트 리스트 확인
helm search repo stable
  
# Repo 정보 갱신
helm repo update

설치 및 저장소 설정이 되었으므로 필요한 애플리케이션들을 저장소를 통해서 쿠버네티스 클러스터에 설치가 가능하다.

Metrics Server 설치

쿠버네티스 클러스터는 기본적으로 모니터링 정보를 알 수 있는 기능이 제공되지 않기 때문에 추가로 설치해야 한다. 기존에는 Heapster 기반으로 구성되었지만 더 이상 개발되지 않고 Metrics Server 로 대체되었다.

따라서 모니터링 기능 (실 시간 정보, 수집된 정보를 메모리에서만 관리하는)을 추가 설치해야 쿠버네티스 컴포넌트들에 대한 자원 모니터링도 가능하고 Autoscaling 에도 사용 가능해진다.

# 최신 버전 다운로드 (현재 v0.4.2)
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

메트릭스 서버가 API Server와 통신할 때 TLS 문제가 존재한다. API Server는 자체 TLS를 사용하지만 메트릭스 서버는 Public TLS를 사용하기 때문에 그냥 설치하면 문제가 발생하게 된다.

따라서 아래와 같이 다운로드한 파일에서 TLS와 hostNetwork 사용 관련된 부분을 수정해 줘야 한다. Tab 키가 아닌 Space 키로 여백을 처리해야 한다.

vi components.yaml
...
      - args:
        - --cert-dir=/tmp        
        - --secure-port=4443        
        - --kubelet-insecure-tls=true     # 이 부분 추가 (TLS 관련)        
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
...      
      hostNetwork: true			  # 이 부분 추가 (Host Network 사용 관련)      
      nodeSelector:
        kubernetes.io/os: linux
...

변경한 components.yaml 파일을 쿠버네티스 클러스터에 배포한다.

# Deploy
kubectl apply -f components.yaml 
  
# Pods 확인
kubectl get pods -n kube-system
  
# Deploy 확인
kubectl get deploy -n kube-system
  
# Node 리소스 사용량 조회
kubectl top node
  
# Pod 리소스 샤용량 조회
kubectl top pod --all-namespaces

참고

Metrics Server 가 배포되어 정상적으로 동작하고 있다고 해도 즉시 데이터를 가져오는 것은 아니다. 따라서 설치 직후에는 다음과 같이 오류 메시지가 나올 수 있다.

Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)

데이터가 수집되지 않아서 처리할 수 없다는 것을 의미한다. 대략 1 ~ 3분 정보 지나서 데이터가 수집되기 시작하면 정상적으로 출력이 된다.

혹시 위의 TLS 및 hostNetwork 관련 수정과 다른 문제가 존재한다면 설정 부분을 다시 확인해야 한다. 이미 배포된 후에 Deployment 옵션을 변경할 경우는 아래의 명령을 사용한다.

kubectl edit deployments.apps -n kube-system metrics-server

참고 자료

댓글

이 블로그의 인기 게시물

OData 에 대해서 알아보자.

얼마 전에 어떤 회사에 인터뷰를 하러 간 적이 있었다. 당시 그 회사는 자체 솔루션을 개발할 기술인력을 찾고 있었고 내부적으로 OData를 사용한다고 했다. 좀 창피한 이야기일 수도 있지만 나름 기술적인 부분에서는 많은 정보를 가지고 있다고 했던 것이 무색하게 OData란 단어를 그 회사 사장님에게서 처음 들었다. 작고, 단순한 사이트들만을 계속해서 작업을 하다 보니 어느덧 큰 줄기들을 잃어버린 것을 느끼기 시작했다. 명색이 개발이 좋고, 기술적인 기반을 만들려고 하는 인간이 단어조차도 모른다는 것은 있을 수 없는 것이라서 다시 새로운 단어들과 개념들을 알아보는 시간을 가지려고 한다. OData (Open Data Protocol) 란? 간단히 정리하면 웹 상에서 손쉽게 데이터를 조회하거나 수정할 수 있도록 주고 받는 웹(프로토콜)을 말한다. 서비스 제공자 입장에서는 웹으로 데이터를 제공하는 방식으로 각 포탈 사이트들이 제공하는 OPEN API 포맷을 독자적인 형식이 아니라 오픈된 공통규약으로 제공 가능하며, 개발자는 이 정보를 다양한 언어의 클라이언트 라이브러리로 어플리케이션에서 소비할 수 있도록 사용하면 된다. 공식 사이트는 www.odata.org 이며 많은 언어들을 지원하고 있다. 좀더 상세하게 정의를 해 보면 OData는 Atom Publishing Protocol  (RFC4287) 의 확장 형식이고 REST (REpresentational State Transfer) Protocol 이다. 따라서 웹 브라우저에서 OData 서비스로 노출된 데이터를 볼 수 있다. 그리고 AtomPub 의 확장이라고 했듯이 데이터의 조회만으로 한정되는 것이 아니라 CRUD 작업이 모두 가능하다. Example 웹 브라우저에서 http://services.odata.org/website/odata.svc 를 열어 보도록 하자. This XML file does not appear to have any style in...

C# 에서 Timer 사용할 때 주의할 점.

예전에 알고 지내시던 분의 질문을 받았다. Windows Forms 개발을 하는데, 주기적 (대략 1분)으로 데이터 요청을 하는 프로그램을 작성하기 위해서 Timer 를 사용하는데, 어떤 기능을 처리해야 하기 때문에 Sleep 을 같이 사용했다고 한다. 여기서 발생하는 문제는 Sleep 5초를 주었더니, Timer 까지 5초 동안 멈춘다는 것이다. Timer 라는 것은 기본적으로 시간의 흐름을 측정하는 기능이기 때문에 Sleep 을 했다고 해서 Timer 가 멈추는 일은 생겨서는 안된다. 그러나 실제 샘플을 만들어 보면 ... Timer 가 Sleep 만큼 동작이 멈추는 것을 확인할 수 있다. Windows Forms 는 UI Thread 를 사용하는 것으로 최적화 되어 있으며 여기서 Timer 를 쓰면 UI Thread 에 최적화된 System.Windows.Forms.Timer 가 사용된다. 여기서 문제의 발생이 시작되는 것이다. Sleep 을 사용하게 되면 UI Thread 가 Sleep 이 걸리기 때문에 여기에 속한 Timer 까지도 멈추는 것이다. 이런 문제를 해결하기 위해서는 System.Threading.Timer 를 사용해야 한다. 이 Timer 는 별도의 Thread 에서 동작하기 때문에 Sleep 의 영향을 받지 않는다. 언뜻 보면 쉬운 해결 방법인 것 같지만 Thread 가 분리되었기 때문에 Timer 가 돌아가는 Thread 에서 UI Thread 의 메서드나 컨트롤에 접근하기 위해서는 별도의 명령을 사용해야 하는 문제가 존재한다. 자~ 그럼 여기서 Timer 에 대해서 다시 한번 정리해 보도록 하자. .NET 에서 제공하는 Timer 들 .NET 에서는 기본적으로 3가지 Timer를 제공하고 있다. (MSDN) System.Windows.Forms.Timer - 사용자가 지정한 간격마다 이벤트를 발생시키며 Windows Forms 응용 프로그램에서 사용할 수 있도록 최적화 되어 있다. System...

[Logging] NLog 사용법 정리...

SCSF 에는 기본적으로 Enterprise Library가 사용된다. 예전에도 그랬지만 기능은 훌륭하고 많은 부분에서 최적화(?)된 것일지도 모르지만, 역시나 사용하기에는 뭔가 모르게 무겁고, 사용하지 않는 기능이 더 많다라는 느낌을 지울수가 없다. 이번 프로젝트도 SCSF를 기반으로 하고 있지만, Enterprise Library를 걷어내고 각 부분에 전문화된 오픈 소스를 사용하기로 하였다. 예전에는 Log4Net을 사용했지만, 대량 사용자 환경에서는 메모리 누수와 기타 문제점이 존재한다는 MS 컨설턴트(?)의 전해진 말을 들은 후로는 사용하지 않는다. 대안으로 사용하는 것이 NLog 이다. 조금 후에는 3.0 버전도 나온다고 홈 페이지에 기재되어 있지만, 그 때가 되면 프로젝트는 끝나기 때문에 현재 2.1.0 버전을 사용하기로 했다. [원본 출처] http://cloverink.net/most-useful-nlog-configurations-closed/ 위의 참조 자료에는 다양한 정보들이 존재하므로 꼭 링크를 통해서 관련된 정보를 확인하고 이해하는 것이 좋을 듯 하다. 여기서는 당장 필요한 부분만을 정리하도록 한다. [ Logger 찾기 ] 기본적으로 Logger가 존재하는 클래스를 기반으로 Logger 정보를 구성한다. Logger logger = LogManager.GetCurrentClassLogger(); 주로 Namespace 기반으로 Logger를 설정하는 경우에 유연하게 사용할 수 있다. 또 다른 방법으로는 지정한 문자열로 특정 Logger를 직접 선택하는 방법도 제공된다. 이를 혼용해서 Namespace와 직접 지정 방식을 같이 사용할 수도 있다. 물론 Logger 환경 설정에서 Wildcard (*)를 지정할 수도 있다. Logger logger = LogManager.GetLogger("Database.Connect"); Logger logger = LogManager.Get...