카테고리 없음

[2023-05-22 월] 앤서블 총정리

16비트 2023. 5. 22. 17:20

 

1. 앤서블 CLI

서버 준비

$ sudo su - root                    // 우분투 서버 루트 사용자로 바꾸기

# cat /etc/ansible/hosts        // 서버 그룹별로 관리 대상 보기

 

센토스 아파치 애드혹 관리

# ansible centos -m yum -a "name=httpd state=present" -k      #centos그룹에 httpd 설치. yum install -y httpd와 같음

# curl https://www.nginx.com/ -o index.html      # nginx 홈페이지에서 index.html 파일을 다운받는다

# ansible centos -m copy -a "src=index.html dest=/var/www/html/index.html" -k    # copy명령은 파일을 전송하는 명령. 관리 서버에서 centos서버 경로로 index.html로 전송한다


# ansible centos -m service -a "name=httpd state=started" -k     # httpd를 기동. systemctl start httpd와 같은 명령


# ansible centos -m shell -a "systemctl status firewalld" -k    # 방화벽이 acitve되었는지 상태를 확인하는 명령


// # ansible centos -m shell -a "systemctl start firewalld" -k    # 방화벽이 멈춰있다면 방화벽을 기동시키는 명령
# ansible centos -m shell -a "firewall-cmd --permanent --zone=public --add-service=http" -k   # httpd 포트 방화벽 허용
# ansible centos -m shell -a "firewall-cmd --reload" -k    # 설정을 변경했으므로 reload해주는 명령

접속테스트

# ansible centos -m service -a "name=httpd state=stopped" -k   # 서비스를 멈추는 명령. systemtctl stop httpd 와 같음
# ansible centos -m shell -a "systemctl stop firewalld" -k       # 방화벽을 멈추는 명령

# ansible centos -m yum -a "name=httpd state=absent" -k    # 서비스를 제거하는 명령. yum remove -y httpd

# ansible centos -m shell -a "systemctl status httpd" -k    # 삭제되어서 상태가 뜨지 않는다

 

우분투 아파치 애드혹 관리

# ansible ubuntu -m apt -a "name=apache2 state=present" -k    # 우분투 서버에 apache를 설치하는 명령
# curl https://www.nginx.com/ -o index.html
// # ansible ubuntu -m copy -a "src=index.html dest=/var/www/html/index.html" -k   # index.html 파일을 우분투 서버 그룹에 전송하는 방법

 # scp index.html root@192.168.1.202:/var/www/html/    # index.html 파일을 원하는 하나의 서버에 전송하는 방법

접속테스트

# ansible ubuntu -m service -a "name=apache2 state=stopped" -k    # 서비스를 멈추는 명령
// # ansible ubuntu -m service -a "name=apache2 state=started" -k 
# ansible ubuntu -m apt -a "name=apache2 state=absent" -k   # 서비스를 지우는 명령. apt remove -y apache2와 같음

 

2. 앤서블 플레이북

멱등성

앤서블은 멱등성(Idempotency)이란 특징을 가집니다. 이는 여러 번 적용해도 결과가 바뀌지 않으며, 수정된 부분이 있다면 그 부분만 새롭게 반영되는 특징이 있다.

 

# echo "172.16.0.100" >> inventory.list      # 파일 내용 마지막 줄에 내용을 추가
# cat inventory.list


# echo "172.16.0.100" >> inventory.list
# cat inventory.list    # 똑같은 내용을 또 입력한다. = 멱등성이 없다

# ansible localhost -c local -m lineinfile -a "path=inventory.list line=172.16.0.200"    # -c는 connection을 뜻하며 ssh를 사용하지 않는 local인 것을 명시함. lineinfile은 문장을 입력하는 명령
# cat inventory.list

# ansible localhost -c local -m lineinfile -a "path=inventory.list line=172.16.0.200"      # 전송은 success이지만 입력은 되지 않는다
# cat inventory.list    # ansible의 lineinfile 명령은 멱등성이 있어서 똑같은 내용을 또 입력하지 않는다



플레이북 구조

YAML 형식으로 작성된 각각의 Playbook들은 하나 이상의 Play를 가지며, 각각의 Play는 하나 이상의 task(앤서블 모듈)을 실행한다

(chef:레시피, puppet:메니페스트)

- name: Playbook Tutorial # - 로 시작하는 3줄이 한 블록이다.
  hosts: all              # ":" 으로 구분해 항목명과 값을 설정한 키-값 형식으로 되어 있다.
  tasks:                  # 항목명의 위치가 정렬되어 있다. yaml은 들여쓰기가 데이터 구조의 깊이가 된다.

센토스, 우분투 아파치 설치 플레이북

현재 파일 목록

# vi apache_install.yml     # 현재 파일에 2개의 play(centos, ubuntu)가 있다
- name: Install apache on centos     # 간략한 설명(생략 가능)
  hosts: centos                 # 서버 그룹에 있는 IP 대상. default는 all임

  tasks:
    - name: install apache web server
      yum: name=httpd state=present # ansible centos -m yum -a "name=httpd state=present" -k   # httpd 설치
    - name: upload default index.html for web server
      get_url: url=https://www.nginx.com dest=/var/www/html/ mode=0644    # index.html 다운로드하고 전송하는 명령. 관리 서버에는 다운로드 파일이 남아있지 않는다.
    - name: start apache web server
      service: name=httpd state=started enabled=yes  # httpd 기동시키는 명령. enabled는 껐다 켜도 httpd가 실행되는 명령

- name: Install apache on ubuntu
  hosts: ubuntu

  tasks:
    - name: install apache web server
      apt: name=apache2 state=present
    - name: upload default index.html for web server
      get_url: url=https://www.nginx.com dest=/var/www/html/ mode=0644
    - name: start apache web server
      service: name=apache2 state=started

# ansible-playbook apache_install.yml -k     # ok는 전에 설치가 되었고 이미 서비스가 기동된 것을 의미. 멱등성의 의미

changed는 실제로 설치가 된 것

 

접속 테스트

 

 

3. 앤서블 환경 설정

센토스, 우분투 아파치 삭제 플레이북

# vi apache_remove.yml
- name: Remove apache on centos
  hosts: centos

  tasks:
    - name: remove apache web server
      yum: name=httpd state=absent

- name: Remove apache on ubuntu
  hosts: ubuntu

  tasks:
    - name: remove apache web server
      apt: name=apache2 state=absent


# ansible-playbook apache_remove.yml -k

 

앤서블 환경 설정 자동화

완전 처음부터 플레이북으로 세팅하기 위해 기존 설정들을 지워준다

# vi /etc/ansible/hosts

G      # 명령줄 제일 아래로 가는 명령

세팅해놓았던 서버 그룹 지우고 저장하고 나오기

 

# vi env.yml

- name: Setup for the Ansible's Environment
  hosts: localhost
  
  tasks:
    - name: Add "/etc/ansible/hosts"
      blockinfile:           # block으로 내용을 추가해줌
        path: /etc/ansible/hosts
        block: |
          [centos]
          192.168.1.212

          [ubuntu]
          192.168.1.202 ansible_python_interpreter=/usr/bin/python3
     
    - name: Configure Bashrc
      lineinfile:     # 원하는 경로에 명령줄 하나를 넣는다
        path: /root/.bashrc
        line: "{{ item }}"
      with_items:    # with 반복을 통해 alias 설정을 해서 단축명령 등록
        - "alias ans='ansible'"
        - "alias anp='ansible-playbook'"


# ansible-playbook env.yml -k

 

# cat /etc/ansible/hosts    # 블록이 잘 추가되었다

# cat .bashrc    # alias가 잘 추가되었다

# source .bashrc     # exit하고 r로 재접속하는 것과 똑같은 기능

이제 ansible을 ans로 쓸 수 있고 ansible-playbook을 anp로 쓸 수 잇다

 

4. 앤서블 Keypair 

known_hosts는 처음 ssh로 접속할 때 안전한 서버인지 물어보고 yes라고 치면 IP가 키와 함께 기록됨

그래서 처음 한 번만 묻고 두 번째부터는 안물어봄

# cat .ssh/known_hosts

서버가 2000대면 yes를 2000번 쳐줘야한다. 그래서 key-pair를 등록해줘야함

# rm -rf .ssh/known_hosts    # 먼저 등록된 IP를 삭제한다

 

# vi keypair_old.yml
- name: Setup for the Ansible's Environment
  hosts: localhost
  
  tasks:
    - name: Generate sshkey
      shell: "{{ item }}"
      with_items:     # 한 줄 입력이 반복적으로 실행됨. 하지만 2000대면 2000대를 적어줘야한다
        - "ssh-keyscan 192.168.1.212 >> ~/.ssh/known_hosts"
        - "ssh-keyscan 192.168.1.202 >> ~/.ssh/known_hosts"

# anp keypair_old.yml -k


# ans all -m ping -k     # IP가 잘 등록되었고 ping이 잘 나간다

 

# rm -rf .ssh/knwon_hosts     # 반복 문제를 해결하는 플레이북을 생성하기 위해 등록한 IP 삭제

 

 

# vi keypair_new.yml
- name: Create known_hosts between server and nodes
  hosts: all         # 관리 서버(centos, ubuntu)를 대상
  connection: local    # 로컬 서버를 대상
  serial: 1       # task 작업을 하나씩 하나씩 처리함. 얘가 없으면 누락이 발생할 수 있음

  tasks:
    - name: ssh-keyscan for known_hosts file
      command: /usr/bin/ssh-keyscan -t ecdsa {{ ansible_host }} # command 명령으로 ecdsa 타입의 

매직변수는 ansible이 설치될 때 ansible이 미리 정해놓은 변수. 매직 변수 ansible_host 활용하여 hosts ip 호출. ansoble_host변수는 hosts파일을 뒤져서 hosts ip를 가져온다
      register: keyscan    # keyscan 변수를 만듦. keyscan을 register(임시로 저장하는 공간)에 저장

    - name: input key
      lineinfile:
        path: ~/.ssh/known_hosts
        line: "{{ item }}"
        create: yes
      with_items:    # 반복문을 통해 item 매개변수에 한 줄씩 들어감. 서버 개수에 상관없이 등록할 수 있다
        - "{{ keyscan.stdout_lines }}"   # 표준 출력

- name: Create authorized_keys between server and nodes       # ansible이 퍼블릭 키와 프라이빗 키를 만들어서 퍼블릭 키를 보내는 명령
  hosts: all
  connection: local
  vars:     # 패스워드를 키에다 집어넣어서 키 인증을 패스워드 없이 접속
    ansible_password: 

  tasks:  
    - name: ssh-keygen for authorized_keys file     
      openssh_keypair:    # 해당 경로에 키 페어(프라이빗 키와 퍼블릭 키)를 생성하는 명령  
        path: ~/.ssh/id_rsa     
        size: 2048    # 암호화 방식의 비트수
        type: rsa    # 비대칭 방식. 암호화, 복호화, 로그인 기능
        force: False     # overwrite하지 않는다는 False라고 값을 넣거나 아니면 삭제하거나 하면 되겠습니다. = 이미 키가 있으면 그것을 활용한다는 명령

    - name: input key for each node
      connection: ssh    # ssh를 통해 모든 호스트에 접속해서 root사용자에게 퍼블릭 키를 전송하는 명령. ssh-copy-id와 같은 명령
      authorized_key:
        user: root
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"    # 위에서 만든 파일 형태의 퍼블릭 키를 가져오는 명령 


 

5. 앤서블 Nginx

# cd .ssh

# rm -rf known_hosts    # 키 인증 방식을 실행하기 위해 known_hosts 파일 삭제

# vi keypair_new.yml

더보기

- name: Create known_hosts between server and nodes
  hosts: all
  connection: local
  serial: 1

  tasks:
    - name: ssh-keyscan for known_hosts file
      command: /usr/bin/ssh-keyscan -t ecdsa {{ ansible_host }} # 매직 변수 ansible_host 활용하여 hosts ip 호출
      register: keyscan

    - name: input key
      lineinfile:
        path: ~/.ssh/known_hosts
        line: "{{ item }}"
        create: yes
      with_items:
        - "{{ keyscan.stdout_lines }}"

- name: Create authorized_keys between server and nodes
  hosts: all
  connection: local
  vars:
    ansible_password: 

  tasks:
    - name: ssh-keygen for authorized_keys file
      openssh_keypair: 
        path: ~/.ssh/id_rsa
        size: 2048
        type: rsa
        force: False # overwrite하지 않는다는 False라고 값을 넣거나 아니면 삭제하거나 하면 되겠습니다.

    - name: input key for each node
      connection: ssh
      authorized_key:
        user: root
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

 

# anp keypair_new.yml

 

# cat .ssh/known_hosts      # 없었던 known_hosts파일이 생겼다

 

iac 서버의 # cat .ssh/peach.pub  내용과 각 서버의 # cat .ssh/authorized_keys의 내용이 똑같다. 퍼블릭 키(자물쇠)가 전송되었다는 뜻

 

# ssh root@192.168.1.212    # 키 인증 방식으로 centos서버와 ubuntu 서버로 비밀번호 없이 접근이 가능하다

# ssh root@192.168.1.202 

 

# ans all -m ping     # -k 명령을 넣지 않아도(패스워드를 입력하지 않아도) ping 명령이 나간다

 

센토스, 우분투 NGINX 설치 플레이북

# vi nginx_install.yml
- name: Install nginx on centos
  hosts: centos

  tasks:    
    - name: install epel-release     # 가장 최신의 저장소를 설치
      yum:     # 3줄로 명령을 적는 방법 (가독성, 취향 차이)
        name: epel-release   
        state: latest
    - name: install nginx web server     # nginx를 설치
      yum: name=nginx state=present    # 1줄로 명령을 적는 방법
    - name: upload default index.html for web server   # index.html 를 다운로드 받아서 centos로 보냄
      get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644
    - name: start nginx web server             # httpd 실행
      service: name=nginx state=started enabled=yes

- name: Install nginx on ubuntu     
  hosts: ubuntu

  tasks:   
    - name: install nginx web server
      apt: pkg=nginx state=present update_cache=yes    # apt update 명령과 같음
    - name: Upload default index.html for web server    # index.html 를 다운로드 받아서 ubuntu로 보냄
      get_url: url=https://www.nginx.com dest=/var/www/html/
               mode=0644 validate_certs=no

더보기

- name: Install nginx on centos
  hosts: centos

  tasks:
    - name: install epel-release
      yum: 
        name: epel-release
        state: latest
    - name: install nginx web server
      yum: name=nginx state=present
    - name: upload default index.html for web server
      get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644
    - name: start nginx web server
      service: name=nginx state=started enabled=yes

- name: Install nginx on ubuntu
  hosts: ubuntu

  tasks:
    - name: install nginx web server
      apt: pkg=nginx state=present update_cache=yes
    - name: Upload default index.html for web server
      get_url: url=https://www.nginx.com dest=/var/www/html/
               mode=0644 validate_certs=no

anp nginx_install.yml       # 설치 파일 실행

 


센토스, 우분투 엔진엑스 삭제 플레이북

# vi nginx_remove.yml
- name: Remove nginx on centos
  hosts: centos

  tasks:
    - name: remove nginx web server
      yum: name=nginx state=absent

- name: Remove nginx on ubuntu
  hosts: ubuntu

  tasks:
    - name: remove nginx web server
      apt: pkg=nginx* state=absent

# anp nginx_remove.yml    # 제거 파일 실행

 

6. 앤서블 NFS

센토스, 우분투 NFS 설치 플레이북

# vi nfs.yml
- name: Setup for nfs server
  hosts: localhost     # local호스트 서버에 nfs 설치

  tasks:

    - name: Open firewall services
      firewalld:   # 방화벽에 nfs를 허용하도록 추가
        permanent: yes
        immediate: yes
        service: "{{ item }}"
        state: enabled
      with_items:
        - rpc-bind
        - nfs
        - mountd

 

    - name: make nfs_shared directory
      file:    # 공유하고 싶은 폴더 생성
        path: /root/nfs_shared 
        state: directory
        mode: 0777

    - name: configure /etc/exports    # 접근할 수 있는 네트워크 범위 설정
      lineinfile:
        path: /etc/exports
        line: /root/nfs_shared 192.168.0.0/21(rw,sync)   # 강의실 IP대역

    - name: Install NFS
      yum:        # nfs-utils 설치 명령
        name: nfs-utils
        state: present

    - name: nfs service start
      service:     # 서버 시작 명령
        name: nfs-server
        state: restarted
        enabled: yes

- name: Setup for nfs clients
  hosts: centos    # CentOS 서버에 nfs-clients 설치

  tasks:
    - name: make nfs_client directory
      file:    # 공유할 파일 생성
        path: /root/nfs
        state: directory

    - name: Install NFS
      yum:    # nfs-utils 설치
        name: nfs-utils
        state: present

    - name: mount point directory as client   # mount -t nfs 192.168.1.166:/root/nfs_shared /root/nfs와 같은 명령
      mount:           # 마운트할 경로 설정
        path: /root/nfs
        src: 192.168.1.166:/root/nfs_shared     # local 서버(ansible서버)의 IP를 소스로 설정
        fstype: nfs
        state: mounted

- name: Setup for nfs clients U
  hosts: ubuntu      # Ubuntu 서버에 nfs-clients 설치

  tasks:
    - name: make nfs_client directory
      file:  # 공유할 파일 생성
        path: /root/nfs
        state: directory

    - name: Install NFS-U
      apt:    # nfs-common 설치
        pkg: nfs-common
        state: present
        update_cache: yes

    - name: mount point directory as client
      mount:  # 마운트할 경로 설정
        path: /root/nfs
        src: 192.168.1.166:/root/nfs_shared    # local 서버(ansible서버)의 IP를 소스로 설정
        fstype: nfs
        opts: nfsvers=3     # nfs 서버 버전을 명시해야한다
        state: mounted

더보기

- name: Setup for nfs server
  hosts: localhost

  tasks:

    - name: open firewall services    
      firewalld:

        permanent: yes

        immediate: yes

        service: "{{ item }}"
        state: enabled
      with_items:

        - rpc-bind

        - nfs

        - mountd
        

    - name: make nfs_shared directory
      file:
        path: /root/nfs_shared
        state: directory
        mode: 0777

    - name: configure /etc/exports
      lineinfile:
        path: /etc/exports
        line: /root/nfs_shared 192.168.0.0/20(rw,sync)

    - name: Install NFS
      yum:
        name: nfs-utils
        state: present

    - name: nfs service start
      service:
        name: nfs-server
        state: restarted
        enabled: yes

- name: Setup for nfs clients
  hosts: centos

  tasks:
    - name: make nfs_client directory
      file:
        path: /root/nfs
        state: directory

    - name: Install NFS
      yum:
        name: nfs-utils
        state: present

    - name: mount point directory as client
      mount:
        path: /root/nfs
        src: 192.168.1.166:/root/nfs_shared
        fstype: nfs
        state: mounted

- name: Setup for nfs clients U
  hosts: ubuntu

  tasks:
    - name: make nfs_client directory
      file:
        path: /root/nfs
        state: directory

    - name: Install NFS-U
      apt:
        pkg: nfs-common
        state: present
        update_cache: yes

    - name: mount point directory as client
      mount:
        path: /root/nfs
        src: 192.168.1.166:/root/nfs_shared
        fstype: nfs
        opts: nfsvers=3
        state: mounted

# anp nfs.yml

 

nfs 테스트     // 우분투 서버에서 txt파일 작성

# ehco "hello wolrd" > nfs/test.txt

centos 서버에서 txt파일 확인

cat nfs/test.txt

 

7. 앤서블 워드프레스

워드프레스 만들기

# vi /etc/ansible/hosts    # centos서버에 웹서버를 설치하고 ubuntu서버에 db서버를 설치할 것이기 때문에 hosts그룹을 수정한다

[webserver]
192.168.1.212

[dbserver]
192.168.1.202 ansible_python_interpreter=/usr/bin/python3

 

 

# vi wordpress.yml
- name: Setup for webserver
  hosts: webserver  # webserver 세팅

  tasks:
    - name: Install http
      yum:    # 설치할 모듈들을 적어놓음
        name: "{{ item }}"
        state: present
      with_items:
        - httpd
        - php
        - php-mysql
        - php-gd
        - php-mbstring
        - wget
        - unzip

    - name: Unarchive a file that needs to be downloaded (added in 2.0)
      ansible.builtin.unarchive:    # 압축된 파일을 다운로드 받고  /var/www/html 경로에 압축을 해제
        src: https://ko.wordpress.org/wordpress-4.8.2-ko_KR.zip
        dest: /var/www/html
        remote_src: yes

    - name: chown
      file:    # apache에 퍼미션을 주고싶은 경로 설정
        path: /var/www/html/wordpress
        owner: "apache"
        group: "apache"
        recurse: "yes"

    - name: web service restart
      service:    # httpd 서비스 재시작
        name: httpd
        state: restarted

- name: Setup for dbserver
  hosts: dbserver    # dbserver 세팅

  tasks:
    - name: Install mariadb
      apt:    # mariadb 설치
        pkg: mariadb-server
        state: present
        update_cache: yes

    - name: Install pymysql
      apt:     # 파이썬을 이용한 mysql연결도구 설치
        pkg: python-pymysql
        state: present

    - name: Install pymysql
      apt:    # 파이썬을 이용한 mysql연결도구 설치
        pkg: python3-pymysql
        state: present

    - name: set root password
      mysql_user:     # mariadb root사용자 패스워드 설정
        name: 'root'
        password: '{{ mysql_root_password }}'        # 비밀번호는 매개변수로 받겠다는 명령
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present

    - name: edit file
      replace:           # bind-adress는 로컬 호스트에서만 mysql 접속하게하는 명령. remote환경에서 접속을 위해 이 명령을 주석처리하는 명령
        path: /etc/mysql/mariadb.conf.d/50-server.cnf
        regexp: "bind-address"
        replace: "#bind-address"

    - name: db service restart
      service:    # mariadb 서비스 재시작
        name: mysql
        state: restarted

    - name: Create database
      mysql_db:      # wordpress 데이터베이스 생성
        db: wordpress
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present

    - name: Create database user
      mysql_user:
        user: wpuser    
        password: wppass
        priv: "wordpress.*:ALL,GRANT"    # wpuser에게 모든 권한을 다준다
        host: '%'     # remote 환경(웹서버)에서 wpuser가 접근할 수 있도록 하는 옵션
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present

더보기

- name: Setup for webserver
  hosts: webserver

  tasks:
    - name: Install http
      yum:
        name: "{{ item }}"
        state: present
      with_items:
        - httpd
        - php
        - php-mysql
        - php-gd
        - php-mbstring
        - wget
        - unzip

    - name: Unarchive a file that needs to be downloaded (added in 2.0)
      ansible.builtin.unarchive:
        src: https://ko.wordpress.org/wordpress-4.8.2-ko_KR.zip
        dest: /var/www/html
        remote_src: yes

    - name: chown
      file:
        path: /var/www/html/wordpress
        owner: "apache"
        group: "apache"
        recurse: "yes"

    - name: web service restart
      service:
        name: httpd
        state: restarted

- name: Setup for dbserver
  hosts: dbserver

  tasks:
    - name: Install mariadb
      apt:
        pkg: mariadb-server
        state: present
        update_cache: yes

    - name: Install pymysql
      apt:
        pkg: python-pymysql
        state: present

    - name: Install pymysql
      apt:
        pkg: python3-pymysql
        state: present

    - name: set root password
      mysql_user:
        name: 'root'
        password: '{{ mysql_root_password }}'
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present

    - name: edit file
      replace:
        path: /etc/mysql/mariadb.conf.d/50-server.cnf
        regexp: "bind-address"
        replace: "#bind-address"

    - name: db service restart
      service:
        name: mysql
        state: restarted

    - name: Create database
      mysql_db:
        db: wordpress
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present

    - name: Create database user
      mysql_user:
        user: wpuser
        password: wppass
        priv: "wordpress.*:ALL,GRANT"
        host: '%'
        login_unix_socket: /var/run/mysqld/mysqld.sock
        state: present


# anp wordpress.yml --extra-vars "mysql_root_password=asdqwe123456"

 

접속 테스트

URL에 '192.168.1.212/wordpress' 입력

 

8. 도커 가상머신 생성

가상머신 그룹으로 묶기

 

도커 가상머신 설치

 

가상머신 이름 docker

스냅샷 찍기