DevOps와 SE를 위한 리눅스 커널 이야기 - 단단한 서버 구축을 위한 12가지 키워드라는 책 스터디를 진행 했었는데 저는 4장 free 명령이 숨기고 있는 것들에 대해서 정리하고 발표 했었습니다. 이 단원의 내용을 블로깅 해둡니다. cpu는 프로세스의 연산 과정에 필요한 리소스 메모리는 프로세스가 연산할 수 있는 공간을 제공해 주는 리소스 cpu가 사람의 뇌 메모리는 사람이 들어 갈 수 있는 공간 프로세스? 프로세스는 메모리라는 공간에 자신이 필요한 함수를 넣어 두거나 변수에 값을 저장하거나 하는 방식으로 연산을 위한 공간을 확보하고 작업을 진행 메모리 부족 연산을 위한 공간을 확보할 수 없고, 시스템 응답 불가 현상, 큰 성능 저하 메모리 사용량 확인하기 free 명령어 전체 메모리 용량, 사용 ..
예전에 헬름 배우기 책을 읽으면서 필요한 내용들을 정리 했었는데 정리되지 않은 내용들이 많아 이해가 되지 않을 수도 있습니다. 참고만 해주시면 좋겠습니다. 헬름 환경 준비 헬름 설정 상위 레포지토리 추가 헬름은 사용자가 설정된 차트 리포지토리를 관리할 수 있도록 repo 하위 명령을 제공한다. $ helm repo add $REPO_NAME $REPO_URL $ helm repo list $ helm repo remove $ helm repo update 헬름 차트 설치 차트 찾기 헬름 차트는 차트 리포지토리에 게시하여 사용할 수 있다. 차트 레포지토리는 패키지화된 차트를 저장하고 공유할 수 있는 위치다. 깃헙 페이지 http 서버 등에 호스팅 될 수 있다. 다양한 차트 레포가 존재한다. 따라서 사용 사..
이번 블로깅은 면접을 위한 CS 전공지식 노트 운영체제 부분을 정리해보았습니다. 운영체제 사용자가 컴퓨터를 쉽게 다루게 해주는 인터페이스, 한정된 메모리나 시스템 자원을 효율적으로 분배함 운영체제에서 소프트웨어를 추가로 설치할 수 없는 것이 펌웨어 운영체제와 컴퓨터 운영체제의 역할과 구조 운영체제의 역할 CPU 스케줄링과 프로세스 관리 메모리 관리 디스크 파일 관리 I/O 디바이스 관리 운영체제의 구조 유저 프로그램 GUI 시스템콜 커널 드라이버: 하드웨어를 제어하기 위한 소프트웨어 하드웨어 가운데의 4개가 운영체제 시스템콜: 운영체제가 커널에 접근하기 위한 인터페이스이며 유저 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출할 때 씀 유저 프로그램이 I/O 요청으로 트랩을 발동하면 올바른 I/..
지옥에서 온 Git 강의를 요약한 블로깅 입니다. 헷갈리는 내용만 적어서 강의랑 같이 봐주시면 좋을 것 같습니다. intro git init 현재 디렉토리에다가 작업을 진행하겠다. git status의 Untracked files 이 파일을 깃한테 버전 관리를 시작하라고 하기전까진 git이 무시한다. git add git한테 관리하라고 얘기를 해주는 것. 최초로 추적할 때도 add를 사용하고, 파일이 변경되고 난 뒤에도 add를 써야한다. git commit 버전은 의미있는 변화라고 말 할 수 있다. 현재 버전의 메세지 이 변화가 어떤 변화를 담고 있는지, 이 파일들이 왜 변경되었는지 그 이유를 적는 것이 변경 메세지, 커밋 메세지 add를 하면 commit 대기 상태에 들어간다. commit 명령을 실..
if(kakao)2022 이게 돼요? 도커 없이 컨테이너 만들기를 정리해봅니다. 저는 ubuntu server 22.04 환경에서 실습을 진행했습니다. 컨테이너 왜 쓸까? 다양한 서버 환경. 서버의 사양, OS 종류, 설치 환경 운영 비용 증가. 애플리케이션이 동작하는 환경 별로 대응이 어려움 서버 환경에 구애 받지 않을 수 있을까? 앱 전용 환경 만들기 패키징 격리 자원 할당 애플리케이션의 전용 환경을 제공합니다. 컨테이너의 사용 요건 리눅스 기술 런타임(컨테이너 관리 도구) 쿠버네티스 실습 환경 구축 root 사용자로 /tmp 디렉토리 밑에서 실습을 진행합니다. sudo -Es cd /tmp # 필요 패키지 설치 apt-get update \ && apt-get -y install gcc \ && a..
포드를 사용하는 상위 오브젝트에는 디플로이먼트 외에도 몇 가지가 더 있는데 상황에 따라서 필요할 수 있는 몇 가지 상위 오브젝트를 공부해봅시다. 잡(Job) 잡은 특정 동작을 수행하고 종료해야 하는 작업을 위한 오브젝트입니다. 포드를 생성해 원하는 동작을 수행한다는 점에서는 디플로이먼트와 같지만, 잡에서 원하는 최종 상태는 '특정 개수의 포드가 실행 중인 것'이 아닌 '포드가 실행되어 정상적으로 종료되는 것'이라는 점에서 차이가 있습니다. 따라서 잡에서는 포드의 컨테이너가 종료 코드로서 0을 반환해 Completed 상태가 되는 것을 목표로 합니다. apiVersion: batch/v1 kind: Job metadata: name: job-hello-world spec: template: spec: re..
이전글입니다. -> 애플리케이션 배포를 위한 고급 설정 기본적인 리소스 외에도 직접 리소스의 종류를 정의해 사용할 수도 있는데, 이를 커스텀 리소스라고 부른다. 커스텀 리소스를 제대로 사용하려면 컨트롤러라고 하는 별도의 컴포넌트를 이해하고 구현할 수 있어야 한다. 쿠버네티스 컨트롤러의 개념과 동작 방식 명령형(Imperative) vs. 선언적(Declarative) 특정 명령을 처리하는 주체와 통신해 그 작업을 수행하고 그 결괏값을 돌려받는 방식을 명령형이라고 말합니다(kubectl run ~). 쿠버네티스는 이와 반대되는 선언형 방식을 지향합니다. 선언형 방식은 최종적으로 도달해야 하는 바람직한 상태를 정의한 뒤, 현재 상태가 바람직한 상태와 다를 경우 이를 일치하도록 만드는 방법입니다. 명령형 방식..
포드의 자원 사용량 제한 쿠버네티스는 컴퓨팅 자원을 컨테이너에 할당하기 위한 여러 기능을 제공합니다. 이 블로깅에서는 포드나 컨테이너에 CPU, 메모리 등의 자원을 할당하는 기본적인 방법을 먼저 알아보고, 쿠버네티스 클러스터 자원의 활용률을 높이기 위한 오버커밋(Overcommit) 방법을 설명합니다. 다음 ResourceQuota와 LimitRanger라는 쿠버네티스 오브젝트의 사용 방법을 다룹니다. 컨테이너와 포드의 자원 사용량 제한: Limit 쿠버네티스는 기본적으로 도커를 컨테이너 런타임으로 사용하기 때문에 포드를 생성할 때 docker와 동일한 원리로 CPU, 메모리의 최대 사용량을 제한할 수 있습니다. # vi resource-limit-pod.yaml apiVersion: v1 kind: P..
여러 명의 개발자가 쿠버네티스에 접근할 수 있고, 각 개발자가 kubectl 같은 명령어를 통해 애플리케이션을 동시에 배포할 수 있어서 보안이 매우 중요합니다. 자주 사용되는 것은 RBAC(Role Based Access Control)를 기반으로 하는 서비스 어카운트 기능입니다. 서비스 어카운트는 사용자 또는 애플리케이션 하나에 해당하며, RBAC라는 기능을 통해 특정 명령을 실행할 수 있는 권한을 서비스 어카운트에 부여합니다. 권한을 부여받은 서비스 어카운트는 해당 권한에 해당하는 기능만 사용할 수 있습니다. 지금까지 kubectl 명령어를 사용해왔던 권한은 사실 최상위에 해당하는, 마치 리눅스의 root 사용자와 같은 권한을 가지고 있습니다. 쿠버네티스의 API에 접근하는 애플리케이션을 운영 환경에..
실습 환경 [k8s]kubeadm, kubelet, kubectl을 설치하여 쿠버네티스(kubernetes) 클러스터 구축하기 모니터링 기본 구조 CAdvisor는 컨테이너에 관련된 모니터링 데이터를 확인할 수 있는 모니터링 도구입니다. 하지만 CAdvisor가 제공하는 웹 UI에서는 단기간의 메트릭만 제공할 뿐, 체계적으로 데이터를 저장하고 분석하지는 않습니다. CAdvisor 같은 모니터링 에이전트 부류의 도구들은 /metrics라고 하는 경로를 외부에 노출시켜 제공합니다. 이 /metrics 경로로 요청을 보내면 CAdvisor는 키-값 쌍으로 구성된 메트릭 데이터의 목록을 반환하는데, 이 메트릭 데이터를 프로메테우스 같은 시계열 데이터베이스에 저장할 수 있습니다. 프로메테우스는 CAdvisor의 ..
kubeadm 설치 방법을 정리해둡니다.. 개발 환경 OS : WIndows 11 pro 가상화 프로그램 : VMware Workstation 16 Player 가상화 OS : Ubuntu Server 20.04.3 LTS 쿠버네티스 클러스터 master 1대, worker 3대 4대 전부 CPU 2core, RAM 4GB, VOLUME 64GB Network Adapter : Bridged(Connected directly to the physical network) 리눅스 설치시에 고정 IP 설정 잘 안될 때는 맨 밑의 참고한 사이트를 확인해주세요!! kubeadm, kubelet, kubectl로 Kubernetes 클러스터 구축 - Master Node 사전 환경 구성 # apt update, u..
들어가기전에 앞서 블로깅에서 사용해왔던 디프롤이먼트는 모두 상태가 없는(stateless) 애플리케이션이었습니다. 즉, 디플로이먼트의 각 포드는 별도의 데이터를 가지고 있지 않았으며, 단순히 요청에 대한 응답만을 반환했습니다. 하지만 데이터베이스처럼 포드 내부에서 특정 데이터를 보유해야 하는, 상태가 있는(stateful) 애플리케이션의 경우에는 데이터를 어떻게 관리할지 고민해야 합니다. 도커의 볼륨처럼 쿠버네티스도 자체에서 호스트에 위치한 디렉터리를 각 포드와 공유함으로써 데이터를 보존하는 것이 가능합니다. 그렇지만 여러 개의 서버로 구성된 쿠버네티스와 같은 클러스터 환경에서는 이 방법이 적합하지 않을 수 있습니다. 쿠버네티스는 워커 노드 중 하나를 선택해 포드를 할당하는데, 특정 노드에서만 데이터를 ..
kops 명령어 설치 $ wget -O kops https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64 $ chmod +x ./kops $ sudo mv ./kops /usr/local/bin/ $ kops version kubectl 명령어 설치 $ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" ..
쿠버네티스 고급 기능 활용 네트워크 7계층에서 가상 호스트를 이용해 서비스 요청을 처리 애플리케이션의 영속적인 데이터를 보관하기 위한 외부 볼륨이 필요 여러 명의 개발자 또는 애플리케이션이 함께 사용하는 쿠버네티스 클러스터에서는 보안을 위해 권한을 관리 특정 포드가 컴퓨팅 자원을 독차지하는 것을 막기 위해 메모리, CPU 사용량의 제한을 위한 체계적인 시스템이 필요 들어가기전에 인그레스는 일반적으로 외부에서 내부로 향하는 것을 지칭하는 단어입니다. 예를 들어 인그레스 트래픽은 외부에서 서버로 유입되는 트래픽을 의미하며, 인그레스 네트워크는 인그레스 트래픽을 처리하기 위한 네트워크를 의미합니다. 인그레스는 외부 요청을 어떻게 처리할 것인지 네트워크 7계층 레벨에서 정의하는 쿠버네티스 오브젝트입니다. 인그레..
이번 블로깅에서는 효율적으로 애플리케이션을 관리하기 위해 자주 사용되는 네임스페이스(Namespace), 컨피그맵(ConfigMap), 시크릿(Secret)의 사용 방법을 알아봅시다. 네임스페이스(Namespace): 리소스를 논리적으로 구분하는 장벽 쿠버네티스에서는 리소스를 논리적으로 구분하기 위해 네임스페이스(Namespace)라는 오프젝트를 제공합니다. 간단히 생각해 네임스페이스는 포드, 레플리카셋, 디플로이먼트, 서비스 등과 같은 쿠버네티스 리소스들이 묶여 있는 하나의 가상 공간 또는 그룹이라고 이해할 수 있습니다. 여러 개의 네임스페이스를 사용하면 마치 하나의 클러스터에서 여러 개의 가상 클러스터를 동시에 사용하는 것처럼 느껴질 것 입니다. 네임스페이스 기본 개념 이해 네임스페이스는 namesp..
서비스(Service): 포드에 연결하고 외부에 노출 디플로이먼트를 통해 생성된 포드에 어떻게 접근할 수 있을까요? 이전 까지는 kubectl describe 명령어로 포드의 내부 IP를 직접 확인한 뒤 포드로 직접 접근할 수는 있었지만, 이 방법은 로컬 개발 환경 또는 쿠버 클러스터 내부에서만 사용할 수 있었습니다. 게다가 도커 컨테이너와 마찬가지로 포드의 IP는 영속적이지 않아 항상 변할 수 있다는 점도 유의해야 합니다. 여러 개의 디플로이먼트를 하나의 완벽한 애플리케이션으로 연동하려면 포드 IP가 아닌, 서로를 발견할 수 있는 다른 방법이 필요합니다. 도커 사용 방법을 되살펴 보면 도커 컨테이너는 -p 옵션으로 손쉽게 컨테이너를 외부로 노출할 수 있었습니다. 즉, 컨테이너가 생성됨과 동시에 외부로 ..
8월 2일부터 깃허브 레포로 진행되는 해커런에 참여했습니다. HackaLearn은 Hackathon + Learn의 합성어로 주어진 기간 안에 관련 지식을 직접 배워서 해커톤에 적용하는 이벤트라고 합니다. Github meetup을 듣다가 알게 된 분을 팔로우 하다가 HackaLearn을 알게되었습니다. hackathon + learn 중에서 learn이 정말 좋았습니다. 많은 사람들이 공부할 수 있도록 Microsoft의 과제 챌린지를 깃허브 레포로 가지고 와서 다같이 챌린지를 달성하고 pull request를 넣는 형태로 learn을 했습니다. learn은 애저 정적 웹앱과 깃허브 액션을 공부했습니다. Github 문서로 깃허브 액션 공부를 하려고 했었는데 이번 기회에 깃허브 액션에 대해 조금 알아 ..
오늘은 작년부터 조금씩 만들어온 사이드 프로젝트가 있는데 한번 소개 해보려고 합니다. 작년 12월부터 띄엄 띄엄.. 만들기 시작했고, 지금은 프로젝트를 업그레이드하여 버전 2.0을 만들고 있는 중입니다. 프로젝트 소개 제가 만든 프로젝트는 카카오 코로나 알리미라는 프로젝트입니다. 카카오 코로나 알리미는 카카오톡을 통해서 코로나 관련 정보를 볼 수 있는 서비스 입니다. 코로나 라이브라는 아주 좋은 서비스가 있지만, 사람들이 카카오톡을 자주 이용하기 때문에 카카오톡 안에 코로나와 관련된 정보를 알려줄 수 있는 서비스를 만들면 좋을 것 같아서 시작하게 됐습니다. 프로젝트 기능 제가 만든 챗봇에는 크게 3가지의 기능이 있습니다. 0시 기준 총 확진자 및 관련 정보들 질병관리청에서 매일 오전에 전날의 확진자 및 ..
백준 1010번 다리 놓기 백준 1010번 다리 놓기 설명 itertools 모듈의 combinations 함수는 너무 느려서 math모듈의 comb 함수를 활용했다. 코드 import sys from math import comb # 조합을 위한 math comb 모듈 input = sys.stdin.readline class Solution: def get_bridge(self, N: int, M: int): # mCn을 반환 return comb(M, N) for _ in range(int(input())): N, M = map(int, input().split()) print(Solution().get_bridge(N, M))
백준 4256번 트리 백준 4256번 트리 설명 전위 순회는 가운데, 왼쪽, 오른쪽으로 가기 때문에 첫번째 값이 가운데 노드이므로 이 노드를 중위 순회에 적용하여 중위 순회를 가운데 노드 기준으로 왼쪽, 오른쪽으로 나누는 분할 정복 형태로 문제를 풉니다. 이렇게 트리를 만들고, 후위 순회로 찍어줍니다. 코드 import sys from typing import List input = sys.stdin.readline # 트리 구조체 선언 class TreeNode: def __init__(self, x, left=None, right=None): self.x = x self.left = left self.right = right class Solution: def tree(self, preorder: L..
백준 13305번 주유소 백준 13305번 주유소 코드 import sys from typing import List input = sys.stdin.readline class Solution: def gas_station(self, N: int, road: List[int], price: List[int]): answer = 0 # 첫번째 주유가격을 저장 money = price[0] for i in range(N-1): # 이전 주유가격보다 더 싼게 나오면 money를 갱신 if price[i] < money: money = price[i] # 그때그때마다 money와 도로를 곱해서 계산해준다. answer += money * road[i] return answer N = int(input()) lo..
백준 1072번 게임 백준 1072번 게임 설명 퍼센트 구할 때 100을 먼저 곱하고 나눠야지 정확하다. 코드 import sys input = sys.stdin.readline class Solution: def game(self, x: int, y: int): # 처음 x, y 퍼센트 percent = int(y*100/x) # 범위 전체로 해서 이분 탐색 start, end = 1, 1000000000 while start < end: mid = (start + end) // 2 # x, y에 mid를 각각 더해서 퍼센트를 구하고, # 처음 x, y의 퍼센트와 비교한다. cur = int((y+mid)*100/(x+mid)) if cur percent else -1 X, Y = map(int, in..
백준 2343번 기타 레슨 백준 2343번 기타 레슨 코드 import sys, math from typing import List input = sys.stdin.readline class Solution: def guitar_lesson(self, N: int, M: int, lesson: List[int]): # 블루레이의 크기로 이분 탐색 # 레슨을 블루레이에 한개씩만 담는다고 했을 때 최소 값을 알 수 있음 # 레슨의 길이중 가장 큰 값이 블루레이의 최소 값이 된다. # 레슨을 싹다 담았을 때가 최대 값 start, end = max(lesson), sum(lesson) answer = sys.maxsize while start mid: count += 1 total = 0 total += le..
개념 자신의 레포지토리를 clone해서 서버로 push하는 경우 그 레포지토리는 origin이라고 할 수 있습니다. 하지만 오픈소스 협업 구조에서는 서버에 있는 레포지토리가 항상 2개 이상(fork를 해서)이라고 볼 수 있습니다. 메인 프로젝트의 레포지토리를 upstream이라고 하고, fork한 자신의 레포지토리를 origin이라고 합니다. 여기서 자신만 commit을 해서 기여하는 것이 아니라 다른사람도 똑같이 clone 및 fork를 해서, pull request를 요청 할 수 있습니다. 그렇기 때문에 본인이 fork해서 commit까지 한 뒤 merge하기 전, 그 시간동안 다른 개발자가 같은 곳에 commit을 하고, merge가 됐으면 충돌이 발생할 수 있습니다. 이때는 어떻게 대응해야 할까요..
백준 14503번 로봇 청소기 백준 14503번 로봇 청소기 코드 import sys from typing import List input = sys.stdin.readline class Solution: def vacuum_cleaner(self, N: int, M: int, r: int, c: int, d: int, board: List[List[int]]): """북, 동, 남, 서 순으로 d가 0, 1, 2, 3 이므로 이걸 인덱스로 해서 x, y 좌표를 만든다.""" x, y = (-1, 0, 1, 0), (0, 1, 0, -1) """빈칸이면 0, 벽이면 1, 청소했으면 2""" board[r][c] = 2 # 처음 값을 청소한 걸로 answer = 1 while True: check = Fa..
글쓰는 또라이가 세상을 바꾼다 - 글또 제 블로그에 오신 모든 분들 안녕하세요. 이번 7월부터 내년 1월까지 글또(글쓰는 또라이가 세상을 바꾼다)모임에 참여하여 활동하게 되었습니다. 첫 번째 글은 글또를 모르시는 분들을 위해서 글또가 어떤 모임인지 그리고 글또를 하게 된 이유, 어떤 글을 쓸지에 대해서 써보려고 합니다. 글또란? 글또는 글 쓰는 또라이가 세상을 바꾼다의 약자로 블로그에 글을 쓰고, 서로 피드백을 해주면서 개발자들의 글쓰기 역량을 키우고, 글을 꾸준히 쓸 수 있게 도와주는 모임입니다. 글또는 2018년부터 시작해서 현재는 6기수가 진행되고 있습니다. 1기에는 13명으로 시작했지만, 현재 약 130명의 개발자분이 참여하고 있습니다. 매 기수를 거쳐오면서 글또는 슬랙에서 채널별로 다양한 활동,..
백준 11727번 2xn 타일링 2 백준 11727번 2xn 타일링 2 설명 타일로 채우는 경우의 수가 크게 3가지가 있다. n일 때 타일을 채우는 방법의 수를 f(n)이라고 하면, f(n-1)에서 2x1 타일 1개를 놓는 경우 f(n-2)에서 1x2 타일 2개를 놓는 경우 f(n-2)에서 2x2 타일 1개를 놓는 경우 f(n-2)에서 2x1 2개를 놓는 경우를 생각 할 수도 있지만, f(n-1)에서 2x1 타일 1개를 놓는 경우와 겹친다. 코드 import sys, collections input = sys.stdin.readline class Solution: def tiling(self, n: int): dp = collections.defaultdict(int) dp[1], dp[2] = 1, 3..
백준 10844번 쉬운 계단 수 백준 10844번 쉬운 계단 수 설명 단순히 점화식을 찾으려고 하면 너무 복잡해진다. 2차원 배열에서의 점화 관계를 사용한다. 위 행렬을 A라고 할 때, A[i][j]는 j로 끝나는 i자리수의 계단의 수이다. 1자리수는 1~9까지 올 수 있으므로 그대로 dp를 채울 수 있고, 2자리수 부터는 0은 전자리수의 1인 경우와 9는 전자리수의 8일 경우이고 나머지는 전자리수의 하나적고 많은 경우의 합이다. 즉 점화식을 dp 배열로 표현하게되면 밑의 코드라고 볼 수 있다. dp[i][0] = dp[i-1][1] dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1] dp[i][9] = dp[i-1][8] 코드 import sys input = sys.stdin.rea..
디플로이먼트(Deployment): 레플리카셋, 포드의 배포를 관리 디플로이먼트 사용하기 실제 쿠버네티스 운영 환경에서 레플리카셋을 YAML 파일에서 사용하는 경우는 거의 없고, 대부분 레플리카셋과 포드의 정보를 정의하는 디플로이먼트(Deployment)라는 이름의 오브젝트를 YAML 파일에 정의해 사용한다. 디플로이먼트는 레플리카셋의 상위 오브젝트이기 때문에 디플로이먼트를 생성하면 해당 디플로이먼트에 대응하는 레플리카셋도 함께 생성된다. # vi deployment-nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx-deployment spec: replicas: 3 selector: matchLabels: app: my-n..
레플리카셋(Replica Set): 일정 개수의 포드를 유지하는 컨트롤러 레플리카셋을 사용하는 이유 쿠버네티스의 기본 단위인 포드는 여러 개의 컨테이너를 추상화해 하나의 애플리케이션으로 동작하도록 만드는 컨테이너 묶음이다. 실제로 외부 사용자의 요청을 처리해야 하는 마이크로 서비스 구조의 포드라면 스웜 모드처럼 여러 개의 동일한 컨테이너를 생성한 뒤 외부 요청이 각 컨테이너에 적절히 분배될 수 있어야 한다. 쿠버네티스에서는 기본 단위가 포드이기 때문에 동일한 여러 개의 포드를 생성해 외부 요청을 각 포드에 분배하는 방식을 사용해야 한다. apiVersion: v1 kind: Pod metadata: name: my-nginx-pod-a spec: containers: - name: my-nginx-con..