2017년 12월 1일 금요일

GDB - Missing separate debuginfos, use: debuginfo-install ...

어라 디버깅이 안 되네.


Missing separate debuginfos, use: debuginfo-install glibc-2.17-55.el7_0.3.x86_64 libgcc-4.8.2-16.2.el7_0.x86_64 libstdc++-4.8.2-16.2.el7_0.x86_64
이런게 gdb 실행 중에 보인다면.

1. debuginfos.


1
2
yum install yum-utils
debuginfo-install glibc libgcc libstdc++
cs


   그럼 문제가 없어진다.


2. 하지만 그래도 안되는 경우엔


   적절한 에디터로 다음 파일을 열어서 /etc/yum.repos.d/CentOS-Debuginfo.repo
   그 중 enabled 값을 1로 변경해 보라고 한다.

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# CentOS-Debug.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
 
# All debug packages from all the various CentOS-7 releases
# are merged into a single repo, split by BaseArch
#
# Note: packages in the debuginfo repo are currently not signed
#
 
[base-debuginfo]
name=CentOS-7 - Debuginfo
baseurl=http://debuginfo.centos.org/7/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
enabled=1
#
cs

2017년 11월 2일 목요일

Dr. Memory

메모리가 새는 곳을 찾아라.


C/C++ 개발을 하다가 보면 동반자와 같은 memory leak ...


1. Valgrind.


   좋은 툴이지만 10년 넘게 사용하다 보니 지겹다.
   좋은 툴이 아니라서 사용 안한게 아니니 오해하기 없기.


2. Dr. Memory.


   새로운 툴을 찾아 열심히 돌아다니던 중 valgrind처럼 오픈 소스인데 윈도우, 리눅스,
   맥, 그리고 안드로이드까지 지원한단다. 거기에다 맙소사 심지어 빠르다.
   Rational Purify를 사용해 보았다면 이게 얼마나 중요한 문제인지 알 수 있는데 ...


3. 설치.


   그냥 Download 에서 사용할 플랫폼에 맞춰 다운로드 후 압축만 풀면 된다.
   적어도 리눅스에선 그렇다.
  


4. 예제 코드.


    굉장히 단순화 되어 있지만 의외로 복잡한 코드에 섞여 있을 때 찾기가 어려웠던 문제.

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
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <map>
 
struct DS {
    int DS_1;
    int DS_2;
};
 
class Base {
    public:
        Base(void) {}
        ~Base(void) {}
};
 
class Derived {
    public:
        Derived(void) {}
        ~Derived(void) {}
        
        std::map<int, DS> m_map;
};
 
int main(int argc, char* args[])
{
    Derived* pD = new Derived();
    pD -> m_map[0= DS();
    Base* pB = static_cast<Base*> (pD);
    delete pB;
}
cs

1
g++ -g ./memoryleaktest.cpp
cs

    그리고 drmemory -- ./a.out 형태로 테스트 가능하다.



5. 결론.


    소멸자를 가상 함수로 만들지 않아 Derived::~Derived 소멸자가 호출되지 않는 문제를
    정확하게 진단해 준다.

6. 그 밖의 옵션들.


    보통 서버는 왠만하면 계속 그냥 떠 있게 된다. 그래서 중간 중간 확인할 수 있는
    방법도 이미 만들어져 있다.

1
drmemory -nudge <PID>
cs

    유용한 옵션으로 로그 저장 경로를 변경 가능하다
1
drmemory -logdir /var/log/DrMemoryLog/ -- ./a.out
cs


2017년 9월 15일 금요일

Bash Prompt Statement variables

Received too large ...


.bashrc 파일에 뭐 좀 이것 저것 추가하고 난 이후에 SCP 접속을 했더니 ...

1. 접속이 안된다.



2. 해결 방법.


   결론부터 요약하면 다음 코드를 출력문 앞에 추가해 준다.

  
1
2
3
if [ -"$PS1" ]; then    
    return
fi
cs

   터미널 접속인지 아닌지 $PS1 값으로 체크해서 터미널 접속인 경우에만
   출력하도록 한다.

2017년 9월 5일 화요일

Sphinx, sphinxcontrib-mermaid 그리고 한글.

'ascii' codec can't encode characters in position -: ordinal not in range(128)


파이썬을 사용하다 보면 늘 만날 수 있는 친숙한 에러 문장이지만 직접 작성한 코드가 아닌
경우라면 난감하기 이를 데가 없겠다.

1. sample.rst


1
2
3
4
5
6
7
.. mermaid::
 
   A[Christmas] --> |Get money|B(Go shopping)
   B --> C{생각 좀 하고}
   C --> |One|D[Laptop]
   C --> |Two|E[iPhone]
   C --> |Three|F[Car]
cs

   위 코드는 Mermaid Live Editor 상에서 다음 그림과 같이 깔끔하게 표시됩니다.

Get money
One
Two
Three
Christmas
Go shopping
생각 좀 하고
Laptop
iPhone
Car

2. make html


   하지만, Sphinx 문서 빌드 명령을 실행하면 정상적으로 실행되지 않습니다.
  
1
2
3
4
5
preparing documents... done
writing output... [100%] rest/Sample
Encoding error:'ascii' codec can't encode characters in position 243-244: ordinal not in range(128)
The full traceback has been saved in /tmp/sphinx-err-mRmF9N.log, if you want to report the issue to the developers.
make: *** [html] Error 1
cs

   하지만 sample.rst의 경우 UTF-8 encoding으로 잘 저장된 파일입니다.
   호출 스택과 같이 디버깅해 보면 unicode 자료형인 code에 한글이 있는 경우
   타입 예측이 실패해서 에러가 발생한 것으로 보인다.

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
Traceback (most recent call last):
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/cmdline.py", line 306, in main
    app.build(opts.force_all, filenames)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/application.py", line 339, in build
    self.builder.build_update()
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/builders/__init__.py", line 331, in build_update
    'out of date' % len(to_build))
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/builders/__init__.py", line 397, in build
    self.write(docnames, list(updated_docnames), method)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/builders/__init__.py", line 434, in write
    self._write_serial(sorted(docnames))
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/builders/__init__.py", line 443, in _write_serial
    self.write_doc(docname, doctree)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/builders/html.py", line 555, in write_doc
    self.docwriter.write(doctree, destination)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/docutils/writers/__init__.py", line 80, in write
    self.translate()
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinx/writers/html.py", line 56, in translate
    self.document.walkabout(visitor)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/docutils/nodes.py", line 174, in walkabout
    if child.walkabout(visitor):
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/docutils/nodes.py", line 174, in walkabout
    if child.walkabout(visitor):
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/docutils/nodes.py", line 166, in walkabout
    visitor.dispatch_visit(self)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/docutils/nodes.py", line 1882, in dispatch_visit
    return method(node)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinxcontrib/mermaid.py", line 281, in html_visit_mermaid
    render_mm_html(self, node, node['code'], node['options'])
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinxcontrib/mermaid.py", line 245, in render_mm_html
    imgcls=None, alt=None)
  File "/home/ships/VirtualEnvironments/Sphinx/lib/python2.7/site-packages/sphinxcontrib/mermaid.py", line 235, in _render_mm_html_raw
    self.body.append(tag_template.format(align=node.get('align'), code=self.encode(code)))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 243-244: ordinal not in range(128)
cs

3. sys.setdefaultencoding


1
2
3
import sys
reload(sys)
sys.setdefaultencoding('UTF-8')
cs

   이렇게 코드에 삽입해도 되지만 다음과 같이 가상 환경의 기본 인코딩을 변경하자.

   VirtualEnvironment/Sphinx/lib64/python2.7/ 경로에 sitecustomize.py 파일을 생성 후
   다음 내용을 입력 후 저장한다.

1
2
3
4
# -*- coding: UTF-8 -*-
 
import sys
sys.setdefaultencoding('UTF-8')
cs

  

3. 결론


   결국 언젠가는 Python 2.X 버전을 대체해야 한다.

2017년 8월 11일 금요일

Grafana docker upgrading.

기억력이 감퇴해서 매번 검색해야 하는 머리를 위해.


거대 프로젝트가 아니라 우리는 Database로 sqlite를 사용합니다.


1. 최선의 방법.


   Installing using Docker 문서를 천천히 읽고 container를 생성할 때 database와 환경
   설정 변수 경로를 host에 맵핑 시키기만 하면 backup / restore 과정이 없어도 됩니다.

  
1
2
3
4
$ docker run -d -p 3000:3000 \
    -v /var/lib/grafana:/var/lib/grafana \
    -e "GF_SECURITY_ADMIN_PASSWORD=secret" \
    grafana/grafana
cs


2. 업그레이드


  
1
2
3
4
docker pull grafana
docker stop my-grafana-container
docker rm my-grafana-container
docker run --name=my-grafana-container --restart=always -/var/lib/grafana:/var/lib/grafana
cs


3. 1번 방법으로 설치하지 않았을 경우.


   sqlite의 경우 grafana.db를 백업해야 합니다. 보통 /var/lib/grafana/grafana.db 경로에
   위치해 있고 설정 파일의 경우 /etc/grafana/grafana.ini 경로에 있습니다.
   설정 파일의 경우엔 버전에 따라 다를 수 있으므로 백업 후 그대로 복구하지 않고
   비교해보고 진행합니다.

   그 외 다른 Database를 사용하는 경우 백업은 Upgrading Grafana 문서를 참조합니다.

  

2017년 8월 7일 월요일

Docker container 그리고 VI.

Debian 계열로 만들어진 이미지를 사용하는 경우 편집기 때문에 애를 먹어서 간단하게 정리해본다.

1. Update.

   2번 명령으로 설치가 안되는 경우 진행.

  
1
sudo apt-get update
cs


2. Install.

  
1
sudo apt-get install vim-full
cs

2017년 8월 4일 금요일

Docker 옵션.

사용중인 옵션을 정리해 본다.


1. --insecure-registry


   private registry 서버를 사용할 때.


2. -g


   Docker image 저장 경로를 변경하고 싶을 때.


3. 예제


  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# /etc/sysconfig/docker
#
# Other arguments to pass to the docker daemon process
# These will be parsed by the sysv initscript and appended
# to the arguments list passed to docker -d
 
other_args="-g /home/ships/docker/ --insecure-registry 192.168.1.100:5000"
DOCKER_CERT_PATH=/etc/docker
 
# Resolves: rhbz#1176302 (docker issue #407)
DOCKER_NOWARN_KERNEL_VERSION=1
 
# Location used for temporary files, such as those created by
# # docker load and build operations. Default is /var/lib/docker/tmp
# # Can be overriden by setting the following environment variable.
# # DOCKER_TMPDIR=/var/tmp
cs

2017년 8월 3일 목요일

How Should I Get Application Configuration into my Docker Containers?

어떻게 다양한 환경에 배포할 수 있을까?


서버를 다 만들고 배포할 때 지금까지는 동일한 환경에서 배포가 가능했다.
그런데 다른 환경에 배포를 하게 되면서 일부 설정이 틀려져야만 하는 상황이 발생한 것이다.
이 글은 인터넷에서 찾은 블로그 게시물을 간단하게 요약한 것임을 밝힙니다.

원문은 How Should I Get Application Configuration into my Docker Containers? 링크를 통해 확인 가능합니다.


1. 지금까지 해왔던 방법.


   이미지를 만들 때 설정 파일을 같이 포함한다.
   그럼 설정이 달라야 하는 서버에 배포하는 경우엔 어떻게 할까?
   우선 컨테이너를 실행한 뒤, 설정 파일을 변경한 후 컨테이너를 재시작.

   장점:
      ■ 설정 파일을 임의로 변경하지 않는 한 모든 컨테이너는 동일하다.

   단점:
      ■ 설정 변경을 위해 docker image를 새로 빌드하거나 우리의 경우처럼 컨테이너를
         직접 수정해야 한다.


2 - 1. 환경 변수로 전달.


   일반적으로 많이 사용되는 방법.

  
1
docker run -e SETTING1=foo -e SETTING2=bar ... <image name>
cs


   장점:
      ■ 1번 방법에 비해 좀 더 동적인 설정이 가능해진다.

   단점:
      ■ 개발 / 서비스 버전의 컨테이너가 변수에 의해 다른 행동을 할 수 있다.
      ■ nginx/apache의 virtual host configuration과 같이 key/value로 정의하기 어려운
         설정이 존재한다.


2 - 2. 환경 변수로 전달.


   2 - 1 방법과 비슷하지만 컨테이너가 시작될 때 직접 전달하는 방법이 아니라
   Consul 또는 etcd처럼 네트웍을 통해서 KV store설정을 사용하는 방법.
   KV store의 경우 계층적 구조를 가질 수도 있기 때문에 key/value 형태의 단순 환경 변수
   전달에 비해 훨씬 더 많은 것들이 가능해진다.
   심지어 confd 같은 경우 KV store가 변경되면 응용 프로그램을 자동으로 재시작 해준다.

   장점:
      ■ 지금까지 이야기했던 방법 중 제일 동적이고 많은 것들을 할 수 있다.

   단점:
      ■ KV store같은 외부 의존성이 생긴다.


3. Docker Volume을 통해 host 파일을 사용.


   이 방법도 기존에 사용하고 있던 방법.

  
1
docker run -/home/ships/my_statsd_config.conf:/etc/statsd.conf hopsoft/graphite-statsd
cs


   장점:
      ■ 임의의 설정 문제로 컨테이너를 변경할 필요가 없습니다.

   단점:
      ■ 배포시 Docker와 별개로 Host OS에 설정 파일을 배포해야 하고 그런 경우
         Ansible, Chef, 또는 Puppet 같은 관리 도구가 별도로 필요할 수 있습니다.

4. 결론.



   경우에 맞게 설정이 얼마나 복잡하고 동적이어야 하는지에 따라 결정.
   배포는 언제나 문제고 어렵다

2017년 3월 7일 화요일

Docker & iptables.

iptables...


개발 PC의 경우엔 방화벽이나 보안이나 특별히 신경쓰지 않는 편이라 ...

1. 서비스 환경.
   Docker 서비스 및 Container가 실행되면서 iptables에 필요한 항목을 자동 추가하는데,
   미리 정의되어 있던 항목에 의해 우선순위에 밀려 적용이 되지 않는 경우가 발생한다.
   이 경우에 iptables를 적용하고 iptables 서비스를 재시작하는 경우 Docker 서비스가
   추가해놓은 설정들이 모두 사라지는 문제가 발생한다.

   그래서 자동으로 추가하지 않도록 하자는 게시물도 존재.

   Docker and IPtables

   어찌 되었던 다행스럽게도 시스템 운영 및 관리는 개발자가 하는게 아니라는...

2017년 2월 20일 월요일

특정 기간에 수정된 파일 찾기 및 복사.

장애 시점에 생성된 파일 찾기.


특별한 내용은 없는데 할 때마다 문서를 찾아야 하는 나쁜 머리를 위해서 기록해둠.

1. find.sh

   코드로 내용은 대체.

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/bin/sh
 
#if [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then
#   echo "$0 $1 $2"
#   touch -t $1 ./startdatetime.noop
#   if [ "$#" -eq 2 ]; then
#       touch -t $2 ./enddatetime.noop
#       find ./ -newer ./startdatetime.noop -a ! -newer ./enddatetime.noop
#   else
#       find ./ -newer ./startdatetime.noop
#   fi
#   rm ./startdatetime.noop
#   if [ "$#" -eq 2 ]; then
#       rm ./enddatetime.noop
#   fi
#   exit 0
#fi
 
recursive_mode=false
enddatetime=$(date +%Y%m%d%H%M.%S)
touch -t $enddatetime ./enddatetime.noop
 
function usage(){
    echo "findr.sh [-r] 200710282133.24 [201502102359.59]"
    echo "          -r : recursive mode (optional)"
    echo "              200710282133.24 : startdatetime (necessary)"
    echo "              [201502102359.59] : enddatetime (optional)"
    echo "  If the end time parameter is omitted, the current time is the end time."
    exit 1
}
 
while getopts ":r :s: :e:" opt; do
    case $opt in
        r)
            echo "-r - Recursive Mode Enable"
            recursive_mode=true
            ;;
        \?)
            echo "Invalid command."
            exit 1
            ;;
    esac
done
 
if [ "$recursive_mode" = true ]; then
    if [ "$#" -ne 2 ] && [ "$#" -ne 3 ]; then
        usage
    else
        touch -t $2 ./startdatetime.noop
        if [ "$#" -eq 3 ]; then
            touch -t $3 ./enddatetime.noop
        fi
        find . -newer ./startdatetime.noop -! -newer ./enddatetime.noop |egrep -"^(./enddatetime.noop)"
    fi
else
    if [ "$#" -ne 1 ] && [ "$#" -ne 2 ]; then
        usage
    else
        touch -t $1 ./startdatetime.noop
        if [ "$#" -eq 2 ]; then
            touch -t $2 ./enddatetime.noop
        fi
        find . -maxdepth 1 -newer ./startdatetime.noop -! -newer ./enddatetime.noop |egrep -"^(./enddatetime.noop)"
    fi
fi
cs

2. cp.

   찾은 파일들을 어딘가로 옮기고 싶을 때는 다음과 같이 한다.

1
mv `find.sh 201702161500.00 201702161505.00` ./../queue/
cs

2017년 2월 16일 목요일

Grafana & graphite 그리고 모니터링 #05.

그런데 그래프가 하루만 그려진다.



모든 준비가 끝나 예쁜 그래프를 보면서 모니터링을 잘 할 수 있을거라 생각했지만...

1. 하루 살이.


   위 그림과 같이 이틀 동안의 그래프를 보도록 설정하고 데이터는 이미 충분히 오랫동안
   수집하고 있는 상태지만 다음 그림과 같이 보인다.


2. storage-schemas.conf.

   파일 이름과 같이 whisper database를 위한 schema를 정의하는 파일입니다.
   파일을 열어보면 앞 부분에 친절하게 적혀 있듯이 위에서부터 순서대로 적용되게 되어
   있어 파일 제일 뒤에 내용을 추가하면 적용되지 않습니다.
   이유는 [default_1min_for_1day] 항목에서 모두 만족하기 때문에 그 다음 항목이 적용
   대상인지 확인할 필요가 없기 때문입니다.

   어쨌든, 그럼 우리가 필요한 schema를 정의해 보도록 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Schema definitions for Whisper files. Entries are scanned in order,
# and first match wins. This file is scanned for changes every 60 seconds.
#  [name]
#  pattern = regex
#  retentions = timePerPoint:timeToStore, timePerPoint:timeToStore, ...
 
# Carbon's internal metrics. This entry should match what is specified in
# CARBON_METRIC_PREFIX and CARBON_METRIC_INTERVAL settings
[carbon]
pattern = ^carbon\.
retentions = 60:90d
 
[sample]
pattern = ^sample\.
retentions = 60s:1d,5m:7d,30m:1y
 
[default_1min_for_1day]
pattern = .*
retentions = 60s:1d
cs

   그리고 graphite container를 재시작 해보지만 역시나 하루만 보이게 됩니다.

3. 해결 방법.

   Whisper database는 rrd와 마찬가지로 최초 schema에 맞춰 database를 생성하고 그 상태
   그대로 유지합니다. 일반적으로는 whisper database file을 삭제하고 재시작 하게 되면
   schema 변경에 맞춰 적용되겠지만 고맙게도 whisper-resize(.py) 라는 도구를
   지원합니다.

   http://github.com/graphite-project/whisper

   위 사이트를 방문해서 whisper-resize에 대한 설명을 확인해 보면 다음과 같이 되어
   있습니다.

   Usage: whisper-resize.py path timePerPoint:timeToStore [timePerPoint:timeToStore]*

   timePerPoint and timeToStore specify lengths of time, for example:

   60:1440      60 seconds per datapoint, 1440 datapoints = 1 day of retention
   15m:8        15 minutes per datapoint, 8 datapoints = 2 hours of retention
   1h:7d        1 hour per datapoint, 7 days of retention
   12h:2y       12 hours per datapoint, 2 years of retention


   Options:
     -h, --help            show this help message and exit
     --xFilesFactor=XFILESFACTOR
                           Change the xFilesFactor
     --aggregationMethod=AGGREGATIONMETHOD
                           Change the aggregation function (average, sum, last,
                           max, min)
     --force               Perform a destructive change
     --newfile=NEWFILE     Create a new database file without removing the
                           existing one
     --nobackup            Delete the .bak file after successful execution
     --aggregate           Try to aggregate the values to fit the new archive
                           better. Note that this will make things slower and use
                           more memory.

   그럼 이제 graphite container에 접속해서 whisper database 수정을 해보자.

1
whisper-resize ./5032.wsp 60s:1d 5m:7d 30m:1y
cs


   이제 다음 그림과 같이 그래프의 왼쪽 영역에도 나오기 시작한다.