Thanks to visit codestin.com
Credit goes to wonnieit.blogspot.com

1장. Reviewing Docker

 ► Container 설계

  • Container는 image기반 실행 프로세스 ( 1 process/container)
    • immutable infra 로 image 생성
    • 경량의 도커 image 생성( through layer 줄이기, Squash 사용 )
    • 실행계정은 root 이외의 실행자
  • 어느 환경에서나 동일한 동작 보장, BORA ( Build Once, Run Anywhere)
  • host machine의 커널의 이용하면서 namespace 분리와 cgroups 이용한 제어를 통해 독립적 os 생성 가능
  • 빠르고 쉽게 시작과 중지

► Docker File 작성법

FROM 문으로 도커 이미지 지정

Image - scratch, alphine, distroless, ubuntu, centos etc

COPY 문으로 빌드할 machine에 있는 file을 container에 복사

ADD 로컬에 있는 gz file extract 해서 파일을 container 에 복사

RUN 문으로 빌드시에 container에서 명령어 실행

ENTRYPOINT, CMD 명령은 container가 기동할 때 실행 명령어

► Image Build

  • docker image build 명령어로 이미지 빌드 ( -t 옵션으로 이름과 태그 지정 )
  • multi-stage build : 여러 컨테이너 이미지를 사용하여 처리하고 결과물만 실행용 컨테이너 이미지에 복사하는 구조 ( 경량화의 방법)
  • Dive를 활용해서 각각 레이어에서 어느 정도 용량 소비되는지 확인 / sqash 사용

► Docker registry 로 Image Push

가상 환경 ex. 아나콘다

  • 게스트OS의 유무? VM vs Docker

가상 머신(VM)

  • Hyperviser(논리적으로 분할된 공간에서 VM 이라는 독립된 가상환경을 만들고 호스트 시스템에서 VM에 깔린 게스트OS를 구동 및 모니터링하는 역할 ) 위에서 guest os 실행
  • VM이 추가될 때 마다 OS를 위한 자원을 할당

도커

  • 로컬 환경 종속 x , os 없이 바로 실행
  • container는 host os kernel 공유

호스트 시스템 : 서버의 OS

게스트 OS : VM 의 OS

하이퍼바이저 : 게스트OS를 구동 및 모니터링

Airflow Best Practices, 에어플로우 좋은 DAG 작성 법

Airflow의 task는 DB에서의 transaction 단위로 봐도 된다.

하나의 task는 complete result를 반환하는게 좋음.

task는 여러번 재실행해도 같은 result여야 함

  • insert x , upsert
  • partition 사용
  • now() 사용 지양

Communication 관련

  • config 파일은 local에 저장 x
  • xcom은 소량의 메세지만 전달하고 큰 데이터는 s3/hdfs사용
  • task는 인증관련 Parameter, password, token 가지고 있으면 안됨 → connection 사용

Top level Python Code!

  • env variables
  • externally py code
  • meta-data file

DAG design → performance and scalability 에 큰 영향

database access, 무거운 computation, networking 작업 지양

Variable 사용 지양 b/c 네트워크 콜, db 접근 양

Variable 사용하는 경우에도 experimental cache 사용 (ttl)

variable << jinja template 사용 b/c variable은 대그 파일이 parse될때마다 caching 안켜져있으면 요청해서 느려짐

Timetables

variable/ connection은 절대 top-level에서 실행 x

DAG 실행 시간까지 미뤄져야 함

변경사항 반영 후 바로 DAG 실행 → 좋지 않음

DAG 변경 후 실행 환경 조정 paramters

DAG complexity 줄이는 법

simplify and optimize your DAGs

  • DAG LOADING 시간 줄이기
  • 간단한 구조 a→b→c 이런 방식의 linear 구조가 delay 줄임
  • 하나의 파일내의 DAG 수 줄이기
  • 효율적 python code 작성, repeated codes 줄이기

참고
https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html#

함수형 컴포넌트

Codestin Search App

함수형 컴포넌트

함수형 컴포넌트 사용법

render 불편

순수함수로도 컴포넌트 선언 가능

import React from "react";


function Hello(props) {
    return (
        <div>Hello {props.name}</div>
    )
}

export default Hello;
import React from "react";


const Hello({name}) =>  {
    return (
        <div>Hello {props.name}</div>
    )
}

export default Hello;

언제 함수형 컴포넌트를 사용해야 할까?

  • react 16 이상에서는 함수형 컴포넌트가 빠름
  • 라이프사이클, state등 불필요한 기능을 제거한 상태이기 때문에 메모리 소모량은 일반 클래스형 컴 포넌트보다 적음
  • state를 사용하는 컴포넌트 개수를 최소화!!!
  • state나 라이프사이클 API 사용할 때만 class로 반환하도록!

Component의 lifecycle method

Codestin Search App

Component의 lifecycle method

  • 리액트 컴포넌트에는 라이프사이클(LifeCycle)(수명 주기)이 존재
  • 컴포넌트 수명은 페이지에 렌더링되기 전 준비 과정에서 시작하여 페이지에서 사라질 때 끝
  • will 접두사- 어떤 작업 작동 전에 실행되는 method
  • did 접두사 -어떤 작업 작동 후에 실행되는 method
  • 라이프사이클은 총 세 가지, 즉 마운트, 업데이트, 언마운트 카테고리 로 나뉨

mount

  • DOM이 생성되고 웹 브라우저상에 나타나는 것
  • 호출 method?
    • constructor → getDerievedStateFromProps → render → componentDidMount
    • constructor ? 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드
      • 컴포넌트를 만들 때 처음으로 실행
      • 초기 state 설정
    • getDerievedStateFromProps? props에 있는 값을 state에 동기 화하는 메서드
    • render? 우리가 준비한 UI를 렌더링하는 메서드
      • 컴포넌트 모양새를 정의
      • this.props, this.state 접근
      • 이 method안에서는 절대 state 변형 불가와 웹 브라우저 접근 x
    • componentDidMount? 컴포넌트가 웹 브라우저상에 나타난 후 호출하는 메서드
      • 컴포넌트를 만들고, 첫 렌더링을 다 마친 후 실행
      • 다른 자바스크립트 라이브러리 또는 프레임워크의 함수를 호출하거나 이벤트 등록, setTimeout, setInterval, 네트워크 요청 같은 비동기 작업을 처리

update

컴포넌트를 업데이트할 때는 다음 총 네 가지 경우

  1. props가 바뀔 때
  1. state가 바뀔 때
  1. 부모 컴포넌트가 리렌더링될 때
  1. this.forceUpdate로 강제로 렌더링을 트리거할 때
  • getDerievedStateFromProps? 마운트 과정에서 도 호출하며, props가 바뀌어서 업데이트할 때도 호출
    • props로 받아온 값을 state에 동기화시키는 용도로 사용
    • component 마운트하거나 props 변경 시 호출
    static getDerievedStateFromProps(nextProps, prevState){
    	if(nextProps.value!==prevState.value){
    //~~ 
    		return {value: nextProps.value};
    }
    return null; //state변경 필요 없으면 
    }
  • shouldComponentUpdate? 컴포넌트가 리렌더링을 해야 할지 말아야 할지를 결정하는 메서드
    • props 또는 state 변경 시 rerendering 시작할지 여부 지정
    • 반드시 true or false 반환
    • 현재 props와 state는 this.props, this.state
    • 새로 설정될 props와 state는 nextProps, nextState
  • render? 컴포넌트를 리렌더링
  • getSnapshotBeforeUpdate? 컴포넌트 변화를 DOM에 반영 하기 바로 직전에 호출하는 메서드
    • snapshot 값으로 전달
  • componentDidUpdate ? 컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드
    • prevProps, prevState 접근 가능

unmount

  • 마운트의 반대 과정, 컴포넌트를 DOM에서 제거하는 것
  • componentWillUnmount? 컴포넌트가 웹 브라우저상에서 사라 지기 전에 호출하는 메서드
    • 컴포넌트를 DOM에서 제거할 때 실행
    • 등록한 이벤트, 타이머, 직접 생성한 DOM이 있다면 여기 에서 제거 작업

사용 예제

LifeCycleSample 컴포넌트 만들기 → App에 rendering → 버튼 누르고 콘솔 창 관리

//LifeCycleSample.js
import React, {Component} from "react";

class LifeCycleSample extends Component{
    state ={
        number:0,
        color:null,
    }

    myRef = null; //ref 설정할 부분

    constructor(props){
        super(props);
        console.log('constructor');
    }

    static getDerievedStateFromProps(nextProps, prevState){
        if(nextProps.color!==prevState.color){
            return{color:nextProps.color};
        }
        return null;
    }

    componentDidMount(){
        console.log('componentDidMount');
    }

    shouldComponentUpdate(nextProps, nextState){
        console.log('shouldComponentUpdate', nextProps, nextState);
        return nextState.number % 10 !==4;
    }

    componentWillUnmount(){
        console.log('componentWillUnmount');
    }

    handleClick = () => {
        this.setState({
            number: this.state.number +1
        });
    }

    getSnapshotBeforeUpdate(prevProps, prevState){
        console.log('getSnapshotBeforeUpdate');
        if(prevProps.color!==this.props.color){
            return this.myRef.style.color;
        }
        return null;
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('componentDidUpdate', prevProps,prevState);
        if(snapshot) {
            console.log('업데이트 되기 직전 색상', snapshot);
        }
    }

    render(){
        console.log('render');

        const style = {
            color: this.props.color
        };

        return (
            <div>
                <h1 style={style} 
            ref={ref=> this.myRef=ref}>{this.state.number}</h1>
            <p>color: {this.state.color}</p>
            <button onClick={this.handleClick}></button>   
            </div>
        )
    }

    
}

export default LifeCycleSample;
//App.js
import logo from './logo.svg';
import './App.css';
import React, {Component} from 'react';
import LifeCycleSample from './LifeCycleSample';



function getRandomColor(){
  return '#' + Math.floor(Math.ramdom() * 16777215).toString(16);
}

class App  extends Component {
  state = {
    color: '#000000'
  }

  handleClick = () => {
    this.setState({
      color : getRandomColor()
    });
  }
  
  
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>random color</button>
        <LifeCycleSample color={this.state.color} />
      </div>
    );
  }

}

export default App;

Component 반복

Codestin Search App

Component반복

리액트 프로젝트에서 반복적인 내용을 효율적으로 보 여 주고 관리하는 방법!

Javascript Array의 map()

  • map 함수는 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 프로세싱한 후 그 결과로 새로운 배열을 생성

arr.map(cb, [thisArg] )

cb? 새로운 배열의 요소를 생성하는 함수

  • cb parameters
    • currentValue : 현재 처리하고 있는 요소
    • index: 현재 처리하고 있는 요소의 index 값
    • array: 현재 처리하고 있는 원본 배열
  • thisArgs
    • callback함수 내부에서 사용할 this reference

var numbers= [1,2,3,4,5]

var processed = numbers.map((num) =>{
    return num*num;
})

console.log(processed); //[ 1, 4, 9, 16, 25 ]
//ES6
var numbers= [1,2,3,4,5]

var processed = numbers.map(num => num*num);

console.log(processed); //[ 1, 4, 9, 16, 25 ]

Key 사용해서 활용

Key사용해서 component 배열을 rendering했을 때 어떤 원소에 변동이 있었는지 알아내기

Key는 유일해야 함, 고윳값

import React, {Component} from 'react';

class Iter extends Component {
    render(){
        const names=['boat','subway','airplane','taxi'];
        const namelist= names.map(
            (name, index) => (<li key={index}>{name}</li>)
        );

        return (
            <ul>
                {namelist}
            </ul>
        )
    }
}



export default Iter;
//App.js
import logo from './logo.svg';
import './App.css';
import React, {Component} from 'react';
import ScrollBox from './Iter';

class App  extends Component {
  render() {
    return (
      <Iter />
    );
  }

}

export default App;

유동적 데이터에 응용

초기 state 설정 → 데이터 추가 기능 구현 → 데이터 제거 기능 구현

//Iter.js
import React, {Component} from 'react';

class Iter extends Component {
    state = {
        names:['boat','subway','airplane','taxi'],
        name : ' '
    }; //기존 상수에 담았던 배열을 컴포넌트의 state에 담기 

    handleChange = (e) =>{
        this.setState({
            name : e.target.value
        });
    }

    handleInsert = ( ) => {
        this.setState({
            names: this.state.names.concat(this.state.name),
            name: ' '
        });
    }

    //요소를 두번 클릭하면 삭제 기능
    handleRemove =(index) =>{
        const {names} = this.state;
        this.setState({
            names:[
                ...names.slice(0,index),
                ...names.slice(index+1,names.length)
            ]
        });
    }

    render(){
        const namelist= this.state.names.map(
            (name, index) => (<li key={index} onDoubleClick={() => {this.handleRemove(index)}}>{name}</li>)
        );

        return (
            <div>
                <input onChange={this.handleChange} value={this.state.name}
                ></input>
                <button onClick={this.handleInsert}>add</button>
                <ul>
                    {namelist}
                </ul>
            </div>
        )
    }
}



export default Iter;
import logo from './logo.svg';
import './App.css';
import React, {Component} from 'react';
import Iter from './Iter';

class App  extends Component {
  render() {
    return (
      <Iter />
    );
  }

}

export default App;

Dom에 이름달기

Codestin Search App

Dom에 이름달기

일반 html에서 DOM 요소에 이름을 달 때는 id 를 사용

<div id=”my element”> </div>

src/index.js 파일 중에 id가 root인 요소에 react component를 rendering하는 코드 있음

... 

const root = ReactDOM.createRoot(document.getElementById('root')); // here! 
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

reportWebVitals();

Reference?

이와 같이 HTML에서 id를 사용하여 DOM에 이름을 다는 것 처럼 react에서도 프로젝트 내부에 DOM 이름 다는 방법!

When to use Reference?

→ DOM을 직접적으로 건드려야 할 때

Example

Process

  • Validation Sample component 만들기
  • input에 ref 달기
  • button 누를 때 마다 input에 fous 추가
// src/ValidationSample.css
.success {
    background-color: : lightgreen;
}

.failure {
    background-color: lightcoral;
}
// src/ValidationSample.js
import React, { Component } from 'react'
import '/ValidationSample.css'; 


class ValidationSample extends Component {
    
    state = {
        password: '',
        clicked: false,
        validated : false
    }
  
    handleChange = (e) => {
        this.setState({
            password: e.target.value 
        });
    }

    handleButtonClick = () => {
        this.setState({
            clicked : true,
            validated: this.state.password === '0000'
        })
    }


    render() {
    return (
      <div>
        <input type='password'
                value={this.state.password}
                onChange={this.handleChange}
                className={this.state.clicked ? (this.state.validated ? 'success' : 'failure') : ' '}></input>
        <button onClick={this.handleButtonClick}>검증하기 </button>
      </div>
    )
  }
}

export default ValidationSample;

DOM을 꼭 사용해야하는 상황

  • 특정 input에 focus주기
  • scroll box 조작
  • canvas 요소에 그림 그리기 등

How to use ref?

props 설정하듯 ref 값으로 callback 함수 전달

<input ref={(ref) ⇒ {this.input=ref}}></input>

this.input은 input의 요소의 DOM을 가리킴

Component에 Ref 달기

주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용시 씀

<MyComponent ref={(ref) => {this.myComponent = ref}}/>

MyComponent 내부 method 및 멤버변수에도 접근 가능, 내부 ref 접근 가능 like handleClick, input등

ex. Scrollbox Component 만들기 → 컴포넌트에 ref달기 → ref이용해서 컴포넌트 내부 메소드 호출

// App.js
import logo from './logo.svg';
import './App.css';
import React, {Component} from 'react';
import ScrollBox from './ScrollBox';

class App  extends Component {
  render() {
    return (
      <div>
        <ScrollBox ref={(ref) => this.scrollBox=ref}/>
        <button onClick={() => this.scrollBox.scrollToBottom()}>맨 밑으로</button> 
      </div> 
    );
  }

}

export default App;
// ScrollBox.js
import React, {Component} from 'react';

class ScrollBox extends Component {
    render(){
        const style = {
            border : '1px solid black',
            height : '300px',
            width : '300px',
            overflow : 'auto',
            position : 'relative'
        };
        const innerstyle = {
            width : '100p%',
            height : '600px',
            background: 'linear-gradient(white,black)'
        };

        scrollToBottom = () => {
            const {scrollHeight, clientHeight } = this.box;
            this.box.scrollTop = scrollHeight- clientHeight;
        } //비구조화 할당 문법 사용 

        return (
            <div style={style}
            ref={(ref)=> {this.box=ref}}><div style={innerstyle} />
            </div>
        )
    }
}



export default ScrollBox;

Event Handling

Codestin Search App

Event Handling

Event?

  • 유저가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것
  • 리액트의 이벤트 시스템은 웹 브라우저의 HTML 이벤트와 인터페 이스가 동일
    render(){
    	return(
    	<div>
    		<p>저는 {this.state.age} 살 입니다 </p>
    		<button onClick={() => {
    			this.setState({
    			number: this. state.number +1})
    		}}> 더하기 </button>
    	</div>
    )
    }

이벤트를 사용할 때 주의 사항

  • 이벤트 이름 camelCase로 작성
  • 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라 함수 형태의 값을 전달
  • DOM 요소에만 이벤트를 설정
    • 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정 불가

이벤트 종류

  • Clipboard
  • Composition
  • Keyboard
  • Focus
  • Form
  • Mouse
  • Selection
  • Touch
  • UI
  • Wheel
  • Media
  • Image
  • Animation
  • Transition

Event Handling 예제

// EventPractice.js
import React, { Component } from 'react';

class EventPractice extends Component {
  render() {
    return (
    <div>
      <h1>EventPractice</h1>
      <input type="text" name="message" placeholder="enter anything"
      onChange ={(e) => {
        console.log(e);
        // e 객체는 Synthetic Event로 웹 브라우저 의 네이티브 이벤트를 감싸는 객체
        console.log(e.target.value); // input안의 값 
      }} />  
    </div>
    );
  }
}

export default EventPractice;
//App.js 
import logo from './logo.svg';
import EventPractice from './EventPractice';
import './App.css';
import { Component } from 'react';

class App extends Component{
  render(){
    return (
      <EventPractice/>
    )
  }
}

export default App;

state에 input 값 담기

import React, { Component } from 'react';

class EventPractice extends Component {
    state = {
        message: ""
    }
    render() {
    return (
        <div>
            <h1>Event Practice</h1>
            <input type="text"
            name="message"
            placeholder='enter anything'
            value={this.state.message}
            onChange={
                (e) => {
                    this.setState({
                        message: e.target.value
                    })
                }
            }
            ></input>
            <button onClick={ () => { //버튼 누를 때 comment 값을 공백으로 설정 
                alert(this.state.message);
                this.setState({
                    message: " "
                });
            }}> OK</button>


        </div>
    );
  }
}

export default EventPractice;

onChange와 onClick에 전달한 한 함수를 따로 빼내서 컴포넌트 임의 method 생성

import React, { Component } from 'react';

class EventPractice extends Component {
    state = {
        message: ''
    }

    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this); // 컴포넌트에 임의 method 만들면 기본적으로 this에 접근할 수 없기에 binding 필요
        this.handleClick = this.handleClick.bind(this);
    }

    handleChange(e){
        this.setState({
            message : e.target.value
        })
    }; 


    handleClick(e){
        alert(this.state.message)
        this.setState({
            message : ""
        });
    }


    render() {
    return (
        <div>
            <h1>Event Practice</h1>
            <input type="text"
            name="message"
            placeholder='enter anything'
            value={this.state.message}
            onChange={ this.handleChange}
            ></input>
            <button onClick={this.handleClick}> OK</button>
        </div>
    );
  }
}

export default EventPractice;

Babel의 transform-class-properties 문법을 사용할 경우에는 화살표 함수 형태로 method 정의

import React, { Component } from 'react';

class EventPractice extends Component {
    state = {
        message: ''
    }


    handleChange = (e) => {
        this.setState({
            message : e.target.value
        })
    }; 


    handleClick = (e) => {
        alert(this.state.message)
        this.setState({
            message : ""
        });
    }


    render() {
    return (
        <div>
            <h1>Event Practice</h1>
            <input type="text"
            name="message"
            placeholder='enter anything'
            value={this.state.message}
            onChange={ this.handleChange}
            ></input>
            <button onClick={this.handleClick}> OK</button>
        </div>
    );
  }
}

export default EventPractice;

Input이 여러개인 경우! event객체 활용하기

import React, { Component } from 'react';

class EventPractice extends Component {
    state = {
        username : '',
        message: ''
    }


    handleChange = (e) => {
        this.setState({
            [e.target.name] : e.target.value // key로 들어가는 것  확인!
        })
    }; 


    handleClick = (e) => {
        alert(this.state.username+' : '+this.state.message)
        this.setState({
            username: "",
            message : ""
        });
    }


    render() {
    return (
        <div>
            <h1>Event Practice</h1>
            <input type="text"
            name="username"
            placeholder='enter your name'
            value={this.state.username}
            onChange={ this.handleChange}
            ></input>
            <input type="text"
            name="message"
            placeholder='enter anything'
            value={this.state.message}
            onChange={ this.handleChange}
            ></input>
            <button onClick={this.handleClick}> OK</button>
        </div>
    );
  }
}

export default EventPractice;

onKeyPress 이벤트핸들링

→ 키를 눌렀을 때 발생하는 KeyPress 이벤트 처리 방식

확인누르면 handleClick 실행

import React, { Component } from 'react';

class EventPractice extends Component {
    state = {
        username : '',
        message: ''
    }


    handleChange = (e) => {
        this.setState({
            [e.target.name] : e.target.value // key로 들어가는 것  확인!
        })
    }; 


    handleClick = (e) => {
        alert(this.state.username+' : '+this.state.message)
        this.setState({
            username: "",
            message : ""
        });
    }

    handleKeyPress = (e) => {
        if (e.key === 'Enter'){
            this.handleClick();
        }
    }


    render() {
    return (
        <div>
            <h1>Event Practice</h1>
            <input type="text"
            name="username"
            placeholder='enter your name'
            value={this.state.username}
            onChange={ this.handleChange}
            ></input>
            <input type="text"
            name="message"
            placeholder='enter anything'
            value={this.state.message}
            onChange={ this.handleChange} onKeyPress={this.handleKeyPress}
            ></input>
            <button onClick={this.handleClick}> OK</button>
        </div>
    );
  }
}

export default EventPractice;

1장. Reviewing Docker

  ► Container 설계 Container는 image기반 실행 프로세스 ( 1 process/container) immutable infra 로 image 생성 경량의 도커 image 생성( through layer 줄이기, Squash...